├── .gitignore ├── test ├── files │ ├── foo │ │ ├── sam.txt │ │ ├── tom.txt │ │ ├── philip.txt │ │ └── sandy.txt │ ├── pjkh.png │ ├── sample.zip │ ├── elfinder.png │ └── README.txt ├── el_finder_test_case.rb ├── test_el_finder_hash.rb ├── el_finder │ ├── test_image.rb │ ├── test_mime_type.rb │ └── test_pathname.rb ├── test_el_finder_symlink.rb ├── test_el_finder_extractors.rb ├── test_el_finder_archivers.rb ├── test_el_finder_thumbs.rb ├── test_el_finder.rb └── test_el_finder_permissions.rb ├── TODO ├── lib ├── el_finder │ ├── version.rb │ ├── image.rb │ ├── mime_type.rb │ ├── pathname.rb │ └── connector.rb └── el_finder.rb ├── Gemfile ├── Rakefile ├── .autotest ├── el_finder.gemspec └── README.rdoc /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | pkg 3 | -------------------------------------------------------------------------------- /test/files/foo/sam.txt: -------------------------------------------------------------------------------- 1 | sam 2 | -------------------------------------------------------------------------------- /test/files/foo/tom.txt: -------------------------------------------------------------------------------- 1 | tom 2 | -------------------------------------------------------------------------------- /test/files/foo/philip.txt: -------------------------------------------------------------------------------- 1 | philip 2 | -------------------------------------------------------------------------------- /test/files/foo/sandy.txt: -------------------------------------------------------------------------------- 1 | sandy 2 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - Complain if root directory is missing. 2 | -------------------------------------------------------------------------------- /lib/el_finder/version.rb: -------------------------------------------------------------------------------- 1 | module ElFinder 2 | VERSION = '1.0.15' 3 | end 4 | -------------------------------------------------------------------------------- /test/files/pjkh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ncoders/el_finder/master/test/files/pjkh.png -------------------------------------------------------------------------------- /test/files/sample.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ncoders/el_finder/master/test/files/sample.zip -------------------------------------------------------------------------------- /test/files/elfinder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ncoders/el_finder/master/test/files/elfinder.png -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | # Specify your gem's dependencies in cyp_mail_processor.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /lib/el_finder.rb: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | 3 | require 'el_finder/pathname' 4 | require 'el_finder/mime_type' 5 | require 'el_finder/image' 6 | require 'el_finder/connector' 7 | -------------------------------------------------------------------------------- /test/files/README.txt: -------------------------------------------------------------------------------- 1 | The files contained within this directory are used solely for testing the ElFinder classes. 2 | The tests rely on the files being exactly as they are. Please do not add/delete/change them. 3 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # -*- ruby -*- 2 | 3 | require 'bundler' 4 | Bundler::GemHelper.install_tasks 5 | 6 | require 'rake/testtask' 7 | Rake::TestTask.new(:test) do |test| 8 | test.libs << 'lib' << 'test' 9 | test.pattern = 'test/**/test_*.rb' 10 | test.verbose = true 11 | end 12 | -------------------------------------------------------------------------------- /test/el_finder_test_case.rb: -------------------------------------------------------------------------------- 1 | require 'test/unit' 2 | require 'el_finder' 3 | require 'pp' 4 | 5 | module ElFinderTestCase 6 | 7 | def setup 8 | @vroot = '/tmp/elfinder' 9 | FileUtils.mkdir_p(@vroot) 10 | FileUtils.cp_r "#{File.dirname(__FILE__)}/files/.", @vroot 11 | @elfinder = ElFinder::Connector.new({ 12 | :root => @vroot, 13 | :url => '/elfinder', 14 | :original_filename_method => lambda {|file| File.basename(file.path)} 15 | }) 16 | end 17 | 18 | def teardown 19 | FileUtils.rm_rf(@vroot) 20 | end 21 | 22 | end 23 | -------------------------------------------------------------------------------- /.autotest: -------------------------------------------------------------------------------- 1 | # -*- ruby -*- 2 | 3 | require 'autotest/restart' 4 | 5 | # Autotest.add_hook :initialize do |at| 6 | # at.extra_files << "../some/external/dependency.rb" 7 | # 8 | # at.libs << ":../some/external" 9 | # 10 | # at.add_exception 'vendor' 11 | # 12 | # at.add_mapping(/dependency.rb/) do |f, _| 13 | # at.files_matching(/test_.*rb$/) 14 | # end 15 | # 16 | # %w(TestA TestB).each do |klass| 17 | # at.extra_class_map[klass] = "test/test_misc.rb" 18 | # end 19 | # end 20 | 21 | # Autotest.add_hook :run_command do |at| 22 | # system "rake build" 23 | # end 24 | -------------------------------------------------------------------------------- /test/test_el_finder_hash.rb: -------------------------------------------------------------------------------- 1 | require 'el_finder_test_case' 2 | 3 | class TestElFinder < Test::Unit::TestCase 4 | 5 | include ElFinderTestCase 6 | 7 | ################################################################################ 8 | 9 | def test_to_hash_method 10 | assert_equal Base64.encode64('foo/bar').chomp, @elfinder.to_hash(ElFinder::Pathname.new(@vroot, 'foo/bar')) 11 | assert_equal Base64.encode64('.').chomp, @elfinder.to_hash(ElFinder::Pathname.new(@vroot)) 12 | end 13 | 14 | def test_from_hash_method 15 | assert_equal File.join(@vroot, 'foo/bar'), @elfinder.from_hash(Base64.encode64('foo/bar').chomp).to_s 16 | assert_equal @vroot, @elfinder.from_hash(Base64.encode64('.').chomp).to_s 17 | end 18 | 19 | end 20 | -------------------------------------------------------------------------------- /test/el_finder/test_image.rb: -------------------------------------------------------------------------------- 1 | require "test/unit" 2 | require "el_finder" 3 | 4 | class TestImage < Test::Unit::TestCase 5 | 6 | def test_that_method_exists 7 | assert_respond_to ElFinder::Image, :size 8 | end 9 | 10 | def test_that_logos_are_correct_size 11 | assert_equal '70x66', ElFinder::Image.size( File.join(File.dirname(__FILE__), '../files/elfinder.png') ) 12 | assert_equal '100x100', ElFinder::Image.size( File.join(File.dirname(__FILE__), '../files/pjkh.png') ) 13 | end 14 | 15 | def test_that_nil_is_returned_on_non_images 16 | assert_equal nil, ElFinder::Image.size( File.join(File.dirname(__FILE__), '../files/README.txt') ) 17 | end 18 | 19 | def test_that_nil_is_returned_on_nonexistint_files 20 | assert_equal nil, ElFinder::Image.size( File.join(File.dirname(__FILE__), '../files/NON_EXIST') ) 21 | end 22 | 23 | end 24 | -------------------------------------------------------------------------------- /test/el_finder/test_mime_type.rb: -------------------------------------------------------------------------------- 1 | require "test/unit" 2 | require "el_finder" 3 | 4 | class TestMimeType < Test::Unit::TestCase 5 | 6 | def test_that_method_exists 7 | assert_respond_to ElFinder::MimeType, :for 8 | end 9 | 10 | def test_known_mime_types 11 | assert_equal 'image/jpeg', ElFinder::MimeType.for('image.jpg') 12 | end 13 | 14 | def test_unknown_mime_types 15 | assert_equal 'unknown/unknown', ElFinder::MimeType.for('image.foo') 16 | end 17 | 18 | def test_uppercase_extensions 19 | assert_equal 'image/jpeg', ElFinder::MimeType.for('image.JPG') 20 | end 21 | 22 | def test_missing_extension 23 | assert_equal 'unknown/unknown', ElFinder::MimeType.for('README') 24 | end 25 | 26 | def test_passing_pathname 27 | assert_equal 'text/plain', ElFinder::MimeType.for(ElFinder::Pathname.new('/tmp', 'README.txt')) 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /lib/el_finder/image.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'shellwords' 3 | require 'image_size' 4 | 5 | module ElFinder 6 | 7 | class Image 8 | 9 | def self.size(pathname) 10 | return nil unless File.exist?(pathname) 11 | s = ::ImageSize.new(File.open(pathname)).size.to_s 12 | s = nil if s.empty? 13 | return s 14 | end 15 | 16 | def self.resize(pathname, options = {}) 17 | return nil unless File.exist?(pathname) 18 | system( ::Shellwords.join(['mogrify', '-resize', "#{options[:width]}x#{options[:height]}!", pathname.to_s]) ) 19 | end # of self.resize 20 | 21 | def self.thumbnail(src, dst, options = {}) 22 | return nil unless File.exist?(src) 23 | system( ::Shellwords.join(['convert', '-resize', "#{options[:width]}x#{options[:height]}", '-background', 'white', '-gravity', 'center', '-extent', "#{options[:width]}x#{options[:height]}", src.to_s, dst.to_s]) ) 24 | end # of self.resize 25 | 26 | end # of class Image 27 | 28 | end # of module ElFinder 29 | -------------------------------------------------------------------------------- /el_finder.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.push File.expand_path("../lib", __FILE__) 3 | require "el_finder/version" 4 | 5 | Gem::Specification.new do |s| 6 | s.name = "el_finder" 7 | s.version = ElFinder::VERSION 8 | s.platform = Gem::Platform::RUBY 9 | s.authors = ["Philip Hallstrom"] 10 | s.email = ["philip@pjkh.com"] 11 | s.homepage = "http://github.com/phallstrom/el_finder" 12 | s.summary = %q{elFinder server side connector for Ruby.} 13 | s.description = %q{Ruby library to provide server side functionality for elFinder. elFinder is an open-source file manager for web, written in JavaScript using jQuery UI.} 14 | 15 | s.rubyforge_project = "el_finder" 16 | 17 | s.files = `git ls-files`.split("\n") 18 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 19 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 20 | s.require_paths = ["lib"] 21 | 22 | s.add_dependency('image_size', '>= 1.0.0') 23 | s.requirements << 'ImageMagick' 24 | 25 | end 26 | -------------------------------------------------------------------------------- /lib/el_finder/mime_type.rb: -------------------------------------------------------------------------------- 1 | module ElFinder 2 | 3 | class MimeType 4 | 5 | TYPES = { 6 | 'ai' => 'application/postscript', 7 | 'eps' => 'application/postscript', 8 | 'exe' => 'application/octet-stream', 9 | 'doc' => 'application/vnd.ms-word', 10 | 'xls' => 'application/vnd.ms-excel', 11 | 'ppt' => 'application/vnd.ms-powerpoint', 12 | 'pps' => 'application/vnd.ms-powerpoint', 13 | 'pdf' => 'application/pdf', 14 | 'xml' => 'application/xml', 15 | 'odt' => 'application/vnd.oasis.opendocument.text', 16 | 'swf' => 'application/x-shockwave-flash', 17 | # archives 18 | 'gz' => 'application/x-gzip', 19 | 'tgz' => 'application/x-gzip', 20 | 'bz' => 'application/x-bzip2', 21 | 'bz2' => 'application/x-bzip2', 22 | 'tbz' => 'application/x-bzip2', 23 | 'zip' => 'application/zip', 24 | 'rar' => 'application/x-rar', 25 | 'tar' => 'application/x-tar', 26 | '7z' => 'application/x-7z-compressed', 27 | # texts 28 | 'txt' => 'text/plain', 29 | 'php' => 'text/x-php', 30 | 'html' => 'text/html', 31 | 'htm' => 'text/html', 32 | 'js' => 'text/javascript', 33 | 'css' => 'text/css', 34 | 'rtf' => 'text/rtf', 35 | 'rtfd' => 'text/rtfd', 36 | 'py' => 'text/x-python', 37 | 'java' => 'text/x-java-source', 38 | 'rb' => 'text/x-ruby', 39 | 'sh' => 'text/x-shellscript', 40 | 'pl' => 'text/x-perl', 41 | 'sql' => 'text/x-sql', 42 | # images 43 | 'bmp' => 'image/x-ms-bmp', 44 | 'jpg' => 'image/jpeg', 45 | 'jpeg' => 'image/jpeg', 46 | 'gif' => 'image/gif', 47 | 'png' => 'image/png', 48 | 'tif' => 'image/tiff', 49 | 'tiff' => 'image/tiff', 50 | 'tga' => 'image/x-targa', 51 | 'psd' => 'image/vnd.adobe.photoshop', 52 | # audio 53 | 'mp3' => 'audio/mpeg', 54 | 'mid' => 'audio/midi', 55 | 'ogg' => 'audio/ogg', 56 | 'mp4a' => 'audio/mp4', 57 | 'wav' => 'audio/wav', 58 | 'wma' => 'audio/x-ms-wma', 59 | # video 60 | 'avi' => 'video/x-msvideo', 61 | 'dv' => 'video/x-dv', 62 | 'mp4' => 'video/mp4', 63 | 'mpeg' => 'video/mpeg', 64 | 'mpg' => 'video/mpeg', 65 | 'mov' => 'video/quicktime', 66 | 'wm' => 'video/x-ms-wmv', 67 | 'flv' => 'video/x-flv', 68 | 'mkv' => 'video/x-matroska' 69 | } 70 | 71 | def self.for(pathname) 72 | pathname = ::Pathname.new(pathname) if pathname.is_a?(String) 73 | TYPES[pathname.extname.downcase[1..-1]] || 'unknown/unknown' 74 | end # of for 75 | 76 | end # of class MimeType 77 | 78 | end # of module ElFinder 79 | -------------------------------------------------------------------------------- /test/test_el_finder_symlink.rb: -------------------------------------------------------------------------------- 1 | require 'el_finder_test_case' 2 | 3 | class TestElFinderSymlink < Test::Unit::TestCase 4 | 5 | include ElFinderTestCase 6 | 7 | ################################################################################ 8 | 9 | def test_ruby_symlink_creation 10 | File.symlink(File.join(@vroot, 'pjkh.png'), File.join(@vroot, 'symlink.png')) 11 | assert File.symlink?(File.join(@vroot, 'symlink.png')) 12 | assert_equal File.join(@vroot, 'pjkh.png'), File.readlink(File.join(@vroot, 'symlink.png')) 13 | 14 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 15 | end 16 | 17 | def test_same_directory 18 | File.symlink(File.join(@vroot, 'pjkh.png'), File.join(@vroot, 'symlink.png')) 19 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 20 | source = r[:cdc].find{|e| e[:name] == 'pjkh.png'} 21 | target = r[:cdc].find{|e| e[:name] == 'symlink.png'} 22 | assert_equal 'image/png', target[:mime] 23 | assert_equal source[:hash], target[:link] 24 | assert_equal 'pjkh.png', target[:linkTo] 25 | assert_equal r[:cwd][:hash], target[:parent] 26 | end 27 | 28 | def test_sub_directory 29 | File.symlink(File.join(@vroot, 'pjkh.png'), File.join(@vroot, 'foo', 'symlink.png')) 30 | 31 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 32 | home = r[:cwd] 33 | source = r[:cdc].find{|e| e[:name] == 'pjkh.png'} 34 | foo = r[:cdc].find{|e| e[:name] == 'foo'} 35 | 36 | h, r = @elfinder.run(:cmd => 'open', :target => foo[:hash]) 37 | target = r[:cdc].find{|e| e[:name] == 'symlink.png'} 38 | 39 | assert_equal source[:hash], target[:link] 40 | assert_equal '../pjkh.png', target[:linkTo] 41 | assert_equal home[:hash], target[:parent] 42 | end 43 | 44 | def test_parent_directory 45 | File.symlink(File.join(@vroot, 'foo', 'tom.txt'), File.join(@vroot, 'symlink.txt')) 46 | 47 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 48 | target = r[:cdc].find{|e| e[:name] == 'symlink.txt'} 49 | foo = r[:cdc].find{|e| e[:name] == 'foo'} 50 | 51 | h, r = @elfinder.run(:cmd => 'open', :target => foo[:hash]) 52 | source = r[:cdc].find{|e| e[:name] == 'tom.txt'} 53 | 54 | 55 | assert_equal source[:hash], target[:link] 56 | assert_equal 'foo/tom.txt', target[:linkTo] 57 | assert_equal foo[:hash], target[:parent] 58 | end 59 | 60 | def test_sibling_directory 61 | FileUtils.mkdir(File.join(@vroot, 'bar')) 62 | File.symlink(File.join(@vroot, 'foo', 'tom.txt'), File.join(@vroot, 'bar', 'symlink.txt')) 63 | 64 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 65 | foo = r[:cdc].find{|e| e[:name] == 'foo'} 66 | bar = r[:cdc].find{|e| e[:name] == 'bar'} 67 | 68 | h, r = @elfinder.run(:cmd => 'open', :target => foo[:hash]) 69 | source = r[:cdc].find{|e| e[:name] == 'tom.txt'} 70 | 71 | h, r = @elfinder.run(:cmd => 'open', :target => bar[:hash]) 72 | target = r[:cdc].find{|e| e[:name] == 'symlink.txt'} 73 | 74 | assert_equal source[:hash], target[:link] 75 | assert_equal '../foo/tom.txt', target[:linkTo] 76 | assert_equal foo[:hash], target[:parent] 77 | end 78 | 79 | end 80 | -------------------------------------------------------------------------------- /test/test_el_finder_extractors.rb: -------------------------------------------------------------------------------- 1 | require 'el_finder_test_case' 2 | 3 | class TestElFinderExtractors < Test::Unit::TestCase 4 | 5 | include ElFinderTestCase 6 | 7 | ################################################################################ 8 | 9 | def test_extract_is_empty_by_default 10 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 11 | assert_equal [], r[:params][:extract] 12 | end 13 | 14 | def test_extract_is_correct_when_set 15 | @elfinder.options = { 16 | :extractors => { 17 | 'application/zip' => ['unzip'], 18 | 'application/x-tar' => ['tar', '-xf'], 19 | 'application/x-gzip' => ['tar', '-xzf'], 20 | 'application/x-bzip2' => ['tar', '-xjf'], 21 | } 22 | } 23 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 24 | assert_equal 4, r[:params][:extract].size 25 | assert r[:params][:extract].include? 'application/zip' 26 | assert r[:params][:extract].include? 'application/x-tar' 27 | assert r[:params][:extract].include? 'application/x-gzip' 28 | assert r[:params][:extract].include? 'application/x-bzip2' 29 | end 30 | 31 | def test_no_extractor_available 32 | @elfinder.options = { :extractors => { 'application/zip' => ['unzip'] } } 33 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 34 | file = r[:cdc].find{|e| e[:name] == 'pjkh.png'} 35 | h, r = @elfinder.run(:cmd => 'extract', :target => file[:hash], :current => r[:cwd][:hash]) 36 | assert_match(/no extractor available/i, r[:error]) 37 | end 38 | 39 | def test_bogus_target 40 | @elfinder.options = { 41 | :extractors => { 'application/zip' => ['unzip'] } 42 | } 43 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 44 | h, r = @elfinder.run(:cmd => 'extract', :target => 'INVALID', :current => r[:cwd][:hash]) 45 | assert_match(/invalid parameters/i, r[:error]) 46 | end 47 | 48 | def test_bogus_current 49 | @elfinder.options = { 50 | :extractors => { 'application/zip' => ['unzip'] } 51 | } 52 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 53 | file = r[:cdc].find{|e| e[:name] == 'sample.zip'} 54 | h, r = @elfinder.run(:cmd => 'extract', :target => file[:hash], :current => 'INVALID') 55 | assert_match(/invalid parameters/i, r[:error]) 56 | end 57 | 58 | def test_permissions_no_read_on_target 59 | @elfinder.options = { 60 | :perms => { 'sample.zip' => {:read => false} }, 61 | :extractors => { 'application/zip' => ['unzip'] } 62 | } 63 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 64 | file = r[:cdc].find{|e| e[:name] == 'sample.zip'} 65 | h, r = @elfinder.run(:cmd => 'extract', :target => file[:hash], :current => r[:cwd][:hash]) 66 | assert_match(/access denied/i, r[:error]) 67 | end 68 | 69 | def test_permissions_no_write_on_current 70 | @elfinder.options = { 71 | :perms => { '.' => {:write => false} }, 72 | :extractors => { 'application/zip' => ['unzip'] } 73 | } 74 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 75 | file = r[:cdc].find{|e| e[:name] == 'sample.zip'} 76 | h, r = @elfinder.run(:cmd => 'extract', :target => file[:hash], :current => r[:cwd][:hash]) 77 | assert_match(/access denied/i, r[:error]) 78 | end 79 | 80 | def test_successful_extraction 81 | raise "Unable to find 'unzip' in your PATH. This test requires unzip to run." if `which unzip`.chomp.empty? 82 | @elfinder.options = { :extractors => { 'application/zip' => ['unzip', '-qq', '-o'] } } 83 | 84 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 85 | file = r[:cdc].find{|e| e[:name] == 'sample.zip'} 86 | h, r = @elfinder.run(:cmd => 'extract', :target => file[:hash], :current => r[:cwd][:hash]) 87 | 88 | assert File.directory?(File.join(@vroot, 'unzipped')) 89 | assert File.exist?(File.join(@vroot, 'unzipped/one')) 90 | assert File.exist?(File.join(@vroot, 'unzipped/two')) 91 | assert File.directory?(File.join(@vroot, 'unzipped/subdir')) 92 | assert File.exist?(File.join(@vroot, 'unzipped/subdir/three')) 93 | assert_not_nil r[:tree] 94 | assert_nil r[:error] 95 | end 96 | 97 | 98 | 99 | ################################################################################ 100 | 101 | 102 | end 103 | -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | == el_finder 2 | 3 | * http://elrte.org/redmine/projects/elfinder 4 | 5 | == Description: 6 | 7 | Ruby library to provide server side functionality for elFinder. elFinder is an 8 | open-source file manager for web, written in JavaScript using jQuery UI. 9 | 10 | == Todo: 11 | 12 | * Document library. 13 | * Document how to implement custom image size/resize methods. 14 | 15 | == Requirements: 16 | 17 | The gem, by default, relies upon the 'image_size' ruby gem and ImageMagick's 'mogrify' and 'convert' commands. 18 | These requirements can be changed by implementing custom methods for determining image size 19 | and resizing of an image. 20 | 21 | NOTE: There is another ruby gem 'imagesize' that also defines the class ImageSize and requires 'image_size' 22 | If you have that one installed, elfinder will fail. Make sure you only have 'image_size' installed if you use 23 | the defaults. 24 | 25 | == Install: 26 | 27 | * Install elFinder (http://elrte.org/redmine/projects/elfinder/wiki/Install_EN) 28 | * Install ImageMagick (http://www.imagemagick.org/) 29 | * Do whatever is necessary for your Ruby framework to tie it together. 30 | 31 | === Rails 3 32 | 33 | * Add "gem 'el_finder'" to Gemfile 34 | * % bundle install 35 | * Switch to using jQuery instead of Prototype 36 | * Add the following action to a controller of your choosing. 37 | 38 | skip_before_filter :verify_authenticity_token, :only => ['elfinder'] 39 | def elfinder 40 | h, r = ElFinder::Connector.new( 41 | :root => File.join(Rails.public_path, 'system', 'elfinder'), 42 | :url => '/system/elfinder', 43 | :perms => { 44 | /^(Welcome|README)$/ => {:read => true, :write => false, :rm => false}, 45 | '.' => {:read => true, :write => false, :rm => false}, # '.' is the proper way to specify the home/root directory. 46 | /^test$/ => {:read => true, :write => true, :rm => false}, 47 | 'logo.png' => {:read => true}, 48 | /\.png$/ => {:read => false} # This will cause 'logo.png' to be unreadable. 49 | # Permissions err on the safe side. Once false, always false. 50 | }, 51 | :extractors => { 52 | 'application/zip' => ['unzip', '-qq', '-o'], # Each argument will be shellescaped (also true for archivers) 53 | 'application/x-gzip' => ['tar', '-xzf'], 54 | }, 55 | :archivers => { 56 | 'application/zip' => ['.zip', 'zip', '-qr9'], # Note first argument is archive extension 57 | 'application/x-gzip' => ['.tgz', 'tar', '-czf'], 58 | }, 59 | 60 | ).run(params) 61 | headers.merge!(h) 62 | render (r.empty? ? {:nothing => true} : {:text => r.to_json}), :layout => false 63 | end 64 | 65 | * Add the appropriate route to config/routes.rb such as: 66 | 67 | match 'elfinder' => 'home#elfinder' 68 | 69 | * Add the following to your layout. The paths may be different depending 70 | on where you installed the various js/css files. 71 | 72 | <%= stylesheet_link_tag 'jquery-ui/base/jquery.ui.all', 'elfinder' %> 73 | <%= javascript_include_tag :defaults, 'elfinder/elfinder.min' %> 74 | 75 | * Add the following to the view that will display elFinder: 76 | 77 | <%= javascript_tag do %> 78 | $().ready(function() { 79 | $('#elfinder').elfinder({ 80 | url: '/elfinder', 81 | lang: 'en' 82 | }) 83 | }) 84 | <% end %> 85 |
86 | 87 | * That's it. I think. If not, check out the example rails application at http://github.com/phallstrom/el_finder-rails-example. 88 | 89 | == License: 90 | 91 | (The MIT License) 92 | 93 | Copyright (c) 2010 Philip Hallstrom 94 | 95 | Permission is hereby granted, free of charge, to any person obtaining 96 | a copy of this software and associated documentation files (the 97 | 'Software'), to deal in the Software without restriction, including 98 | without limitation the rights to use, copy, modify, merge, publish, 99 | distribute, sublicense, and/or sell copies of the Software, and to 100 | permit persons to whom the Software is furnished to do so, subject to 101 | the following conditions: 102 | 103 | The above copyright notice and this permission notice shall be 104 | included in all copies or substantial portions of the Software. 105 | 106 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 107 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 108 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 109 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 110 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 111 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 112 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 113 | -------------------------------------------------------------------------------- /test/test_el_finder_archivers.rb: -------------------------------------------------------------------------------- 1 | require 'el_finder_test_case' 2 | 3 | class TestElFinderExtractors < Test::Unit::TestCase 4 | 5 | include ElFinderTestCase 6 | 7 | ################################################################################ 8 | 9 | def test_archive_is_empty_by_default 10 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 11 | assert_equal [], r[:params][:archives] 12 | end 13 | 14 | def test_archive_is_correct_when_set 15 | @elfinder.options = { 16 | :archivers => { 17 | 'application/zip' => ['.zip', 'zip', '-qr9'], 18 | 'application/x-tar' => ['.tar', 'tar', '-cf'], 19 | 'application/x-gzip' => ['.tgz', 'tar', '-czf'], 20 | 'application/x-bzip2' => ['.tbz', 'tar', '-cjf'], 21 | } 22 | } 23 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 24 | assert_equal 4, r[:params][:archives].size 25 | assert r[:params][:archives].include? 'application/zip' 26 | assert r[:params][:archives].include? 'application/x-tar' 27 | assert r[:params][:archives].include? 'application/x-gzip' 28 | assert r[:params][:archives].include? 'application/x-bzip2' 29 | end 30 | 31 | def test_no_archiver_available 32 | @elfinder.options = { :archivers => { 'application/zip' => ['zip', '-qr9'] } } 33 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 34 | files = r[:cdc].select{|e| e[:name] =~ /\.png$/} 35 | h, r = @elfinder.run(:cmd => 'archive', :type => 'bogus/archiver', :targets => files.map{|f| f[:hash]}, :current => r[:cwd][:hash]) 36 | assert_match(/no archiver available/i, r[:error]) 37 | end 38 | 39 | def test_bogus_target 40 | @elfinder.options = { :archivers => { 'application/zip' => ['zip', '-qr9'] } } 41 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 42 | h, r = @elfinder.run(:cmd => 'archive', :type => 'application/zip', :targets => ['INVALID'], :current => r[:cwd][:hash]) 43 | assert_match(/invalid parameters/i, r[:error]) 44 | end 45 | 46 | def test_bogus_current 47 | @elfinder.options = { :archivers => { 'application/zip' => ['.zip', 'zip', '-qr9'] } } 48 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 49 | files = r[:cdc].select{|e| e[:name] =~ /\.png$/} 50 | h, r = @elfinder.run(:cmd => 'archive', :type => 'application/zip', :targets => files.map{|f| f[:hash]}, :current => 'INVALID') 51 | assert_match(/invalid parameters/i, r[:error]) 52 | end 53 | 54 | def test_permissions_no_read_on_target 55 | @elfinder.options = { 56 | :perms => { 'pjkh.png' => {:read => false} }, 57 | :archivers => { 'application/zip' => ['.zip', 'zip', '-qr9'] } 58 | } 59 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 60 | files = r[:cdc].select{|e| e[:name] =~ /\.png$/} 61 | h, r = @elfinder.run(:cmd => 'archive', :type => 'application/zip', :targets => files.map{|f| f[:hash]}, :current => r[:cwd][:hash]) 62 | assert_match(/access denied/i, r[:error]) 63 | end 64 | 65 | def test_permissions_no_write_on_current 66 | @elfinder.options = { 67 | :perms => { '.' => {:write => false} }, 68 | :archivers => { 'application/zip' => ['.zip', 'zip', '-qr9'] } 69 | } 70 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 71 | files = r[:cdc].select{|e| e[:name] =~ /\.png$/} 72 | h, r = @elfinder.run(:cmd => 'archive', :type => 'application/zip', :targets => files.map{|f| f[:hash]}, :current => r[:cwd][:hash]) 73 | assert_match(/access denied/i, r[:error]) 74 | end 75 | 76 | def test_successful_archive 77 | raise "Unable to find 'zip' in your PATH. This test requires zip to run." if `which zip`.chomp.empty? 78 | @elfinder.options = { :archivers => { 'application/zip' => ['.zip', 'zip', '-qr9'] } } 79 | 80 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 81 | files = r[:cdc].select{|e| e[:name] =~ /\.png$/} 82 | h, r = @elfinder.run(:cmd => 'archive', :name => 'Archive', :type => 'application/zip', :targets => files.map{|f| f[:hash]}, :current => r[:cwd][:hash]) 83 | 84 | assert File.exist?(File.join(@vroot, 'Archive.zip')) 85 | assert_not_nil r[:select] 86 | assert_nil r[:error] 87 | end 88 | 89 | def test_successful_archive_with_default_name 90 | raise "Unable to find 'zip' in your PATH. This test requires zip to run." if `which zip`.chomp.empty? 91 | @elfinder.options = { :archivers => { 'application/zip' => ['.zip', 'zip', '-qr9'] } } 92 | 93 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 94 | files = r[:cdc].select{|e| e[:name] =~ /\.png$/} 95 | h, r = @elfinder.run(:cmd => 'archive', :type => 'application/zip', :targets => files.map{|f| f[:hash]}, :current => r[:cwd][:hash]) 96 | 97 | assert File.exist?(File.join(@vroot, "#{files.first[:name].chomp('.png')}.zip")) 98 | assert_not_nil r[:select] 99 | assert_nil r[:error] 100 | end 101 | 102 | 103 | ################################################################################ 104 | 105 | 106 | end 107 | -------------------------------------------------------------------------------- /lib/el_finder/pathname.rb: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | require 'pathname' 3 | 4 | module ElFinder 5 | 6 | class Pathname 7 | attr_reader :root, :path 8 | 9 | # 10 | def initialize(root, path = '.') 11 | @root = root.is_a?(ElFinder::Pathname) ? root.root : ::Pathname.new(root) 12 | 13 | @path = ::Pathname.new(path) 14 | @path = path.is_a?(ElFinder::Pathname) ? path.path : ::Pathname.new(path) 15 | if absolute? 16 | if @path.cleanpath.to_s.start_with?(@root.to_s) 17 | @path = ::Pathname.new @path.to_s.slice((@root.to_s.length + 1)..-1) 18 | elsif @path.cleanpath.to_s.start_with?(@root.realpath.to_s) 19 | @path = ::Pathname.new @path.to_s.slice((@root.realpath.to_s.length + 1)..-1) 20 | else 21 | raise SecurityError, "Absolute paths are not allowed" 22 | end 23 | end 24 | raise SecurityError, "Paths outside the root are not allowed" if outside_of_root? 25 | 26 | end # of initialize 27 | 28 | # 29 | def +(other) 30 | if other.is_a? ::ElFinder::Pathname 31 | other = other.path 32 | end 33 | self.class.new(@root, (@path + other).to_s) 34 | end # of + 35 | 36 | # 37 | def is_root? 38 | @path.to_s == '.' 39 | end 40 | 41 | # 42 | def absolute? 43 | @path.absolute? 44 | end # of absolute? 45 | 46 | # 47 | def relative? 48 | @path.relative? 49 | end # of relative? 50 | 51 | # 52 | def outside_of_root? 53 | !cleanpath.to_s.start_with?(@root.to_s) 54 | end # of outside_of_root? 55 | 56 | # 57 | def fullpath 58 | @path.nil? ? @root : @root + @path 59 | end # of fullpath 60 | 61 | # 62 | def cleanpath 63 | fullpath.cleanpath 64 | end # of cleanpath 65 | 66 | # 67 | def realpath 68 | fullpath.realpath 69 | end # of realpath 70 | 71 | # 72 | def basename(*args) 73 | @path.basename(*args) 74 | end # of basename 75 | 76 | # 77 | def basename_sans_extension 78 | @path.basename(@path.extname) 79 | end # of basename 80 | 81 | # 82 | def basename(*args) 83 | @path.basename(*args) 84 | end # of basename 85 | 86 | # 87 | def dirname 88 | self.class.new(@root, @path.dirname) 89 | end # of basename 90 | 91 | # 92 | def extname 93 | @path.nil? ? '' : @path.extname 94 | end # of extname 95 | 96 | # 97 | def to_s 98 | cleanpath.to_s 99 | end # of to_s 100 | alias_method :to_str, :to_s 101 | 102 | 103 | # 104 | def children(with_directory=true) 105 | realpath.children(with_directory).map{|e| self.class.new(@root, e)} 106 | end 107 | 108 | # 109 | def touch(options = {}) 110 | FileUtils.touch(cleanpath, options) 111 | end 112 | 113 | # 114 | def relative_to(other) 115 | @path.relative_path_from(other) 116 | end 117 | 118 | # 119 | def unique 120 | return self.dup unless self.file? 121 | copy = 1 122 | begin 123 | new_file = self.class.new(@root, dirname + "#{basename_sans_extension} #{copy}#{extname}") 124 | copy += 1 125 | end while new_file.exist? 126 | new_file 127 | end # of unique 128 | 129 | # 130 | def duplicate 131 | _basename = basename_sans_extension 132 | copy = 1 133 | if _basename.to_s =~ /^(.*) copy (\d+)$/ 134 | _basename = $1 135 | copy = $2.to_i 136 | end 137 | begin 138 | new_file = self.class.new(@root, dirname + "#{_basename} copy #{copy}#{extname}") 139 | copy += 1 140 | end while new_file.exist? 141 | new_file 142 | end # of duplicate 143 | 144 | # 145 | def rename(to) 146 | to = self.class.new(@root, to.to_s) 147 | realpath.rename(to.fullpath.to_s) 148 | rescue Errno::EXDEV 149 | FileUtils.move(realpath.to_s, to.fullpath.to_s) 150 | ensure 151 | @path = to.path 152 | end # of rename 153 | 154 | { 155 | 'directory?' => {:path => 'realpath', :rescue => true }, 156 | 'exist?' => {:path => 'realpath', :rescue => true }, 157 | 'file?' => {:path => 'realpath', :rescue => true }, 158 | 'ftype' => {:path => 'realpath', }, 159 | 'mkdir' => {:path => 'fullpath', :args => '(*args)' }, 160 | 'mkdir' => {:path => 'fullpath', :args => '(*args)' }, 161 | 'mtime' => {:path => 'realpath', }, 162 | 'open' => {:path => 'fullpath', :args => '(*args, &block)' }, 163 | 'read' => {:path => 'fullpath', :args => '(*args)' }, 164 | 'readlink' => {:path => 'fullpath', }, 165 | 'readable?' => {:path => 'realpath', :rescue => true }, 166 | 'size' => {:path => 'realpath', }, 167 | 'symlink?' => {:path => 'fullpath', }, 168 | 'unlink' => {:path => 'realpath', }, 169 | 'writable?' => {:path => 'realpath', :rescue => true }, 170 | }.each_pair do |meth, opts| 171 | class_eval <<-METHOD, __FILE__, __LINE__ + 1 172 | def #{meth}#{opts[:args]} 173 | #{opts[:path]}.#{meth}#{opts[:args]} 174 | #{"rescue Errno::ENOENT\nfalse" if opts[:rescue]} 175 | end 176 | METHOD 177 | end 178 | 179 | 180 | end # of class Pathname 181 | 182 | end # of module ElFinder 183 | -------------------------------------------------------------------------------- /test/test_el_finder_thumbs.rb: -------------------------------------------------------------------------------- 1 | require 'el_finder_test_case' 2 | 3 | class TestElFinderThumbs < Test::Unit::TestCase 4 | 5 | include ElFinderTestCase 6 | 7 | ################################################################################ 8 | 9 | def test_tmb_is_false_by_default 10 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 11 | assert_equal nil, r[:tmb] 12 | end 13 | 14 | def test_thumbs_directory_does_not_show_in_output 15 | @elfinder.options = { :thumbs => true, :thumbs_directory => '.thumbs' } 16 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 17 | target = r[:cdc].find{|e| e[:name] == '.thumbs'} 18 | assert_equal true, target.nil? 19 | end 20 | 21 | def test_thumbs_directory_exists 22 | @elfinder.options = { :thumbs => true, :thumbs_directory => '.thumbs' } 23 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 24 | assert File.directory?(File.join(@vroot, '.thumbs')) 25 | end 26 | 27 | def test_thumbs_directory_cannot_be_created 28 | FileUtils.touch(File.join(@vroot, '.thumbs')) 29 | @elfinder.options = { :thumbs => true, :thumbs_directory => '.thumbs' } 30 | assert_raise RuntimeError do 31 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 32 | end 33 | end 34 | 35 | # 36 | # In the root there are a two images: elfinder.png, pjkh.png 37 | # 38 | 39 | def test_tmb_is_true_when_thumbs_enabled_and_images_exist_without_thumbnail 40 | @elfinder.options = { :thumbs => true } 41 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 42 | assert_equal true, r[:tmb] 43 | end 44 | 45 | def test_tmb_is_false_when_thumbs_enabled_and_images_exist_with_thumbnail 46 | @elfinder.options = { :thumbs => true } 47 | Dir.mkdir(File.join(@vroot, '.thumbs')) 48 | FileUtils.touch(File.join(@vroot, '.thumbs', "#{@elfinder.to_hash(ElFinder::Pathname.new(@vroot, 'elfinder.png'))}.png")) 49 | FileUtils.touch(File.join(@vroot, '.thumbs', "#{@elfinder.to_hash(ElFinder::Pathname.new(@vroot, 'pjkh.png'))}.png")) 50 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 51 | assert_equal nil, r[:tmb] 52 | end 53 | 54 | def test_thumbs_are_created_when_requested 55 | @elfinder.options = { :thumbs => true } 56 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 57 | h, r = @elfinder.run(:cmd => 'tmb', :current => '') 58 | assert File.exist?(File.join(@vroot, '.thumbs', "#{@elfinder.to_hash(ElFinder::Pathname.new(@vroot, 'elfinder.png'))}.png")) 59 | assert File.exist?(File.join(@vroot, '.thumbs', "#{@elfinder.to_hash(ElFinder::Pathname.new(@vroot, 'pjkh.png'))}.png")) 60 | end 61 | 62 | def test_thumbs_of_non_images_are_not_created 63 | @elfinder.options = { :thumbs => true } 64 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 65 | h, r = @elfinder.run(:cmd => 'tmb', :current => '') 66 | assert !File.exist?(File.join(@vroot, '.thumbs', "#{@elfinder.to_hash(ElFinder::Pathname.new(@vroot, 'README.txt'))}.png")) 67 | end 68 | 69 | def test_tmb_response 70 | @elfinder.options = { :thumbs => true } 71 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 72 | h, r = @elfinder.run(:cmd => 'tmb', :current => '') 73 | 74 | elfinder_hash = @elfinder.to_hash(ElFinder::Pathname.new(@vroot, 'elfinder.png')) 75 | pjkh_hash = @elfinder.to_hash(ElFinder::Pathname.new(@vroot, 'pjkh.png')) 76 | 77 | assert_equal 2, r[:images].size 78 | assert_equal "/elfinder/.thumbs/#{elfinder_hash}.png", r[:images][elfinder_hash] 79 | assert_equal "/elfinder/.thumbs/#{pjkh_hash}.png", r[:images][pjkh_hash] 80 | end 81 | 82 | def test_tmb_more_to_be_created 83 | @elfinder.options = { :thumbs => true, :thumbs_at_once => 1 } 84 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 85 | h, r = @elfinder.run(:cmd => 'tmb', :current => '') 86 | 87 | elfinder_hash = @elfinder.to_hash(ElFinder::Pathname.new(@vroot, 'elfinder.png')) 88 | pjkh_hash = @elfinder.to_hash(ElFinder::Pathname.new(@vroot, 'pjkh.png')) 89 | 90 | assert_equal true, r[:tmb] 91 | assert_equal 1, r[:images].size 92 | end 93 | 94 | def test_thumbnail_removed_when_image_removed 95 | @elfinder.options = { :thumbs => true } 96 | pjkh_thumb = File.join(@vroot, '.thumbs', "#{@elfinder.to_hash(ElFinder::Pathname.new(@vroot, 'pjkh.png'))}.png") 97 | elfinder_thumb = File.join(@vroot, '.thumbs', "#{@elfinder.to_hash(ElFinder::Pathname.new(@vroot, 'elfinder.png'))}.png") 98 | Dir.mkdir(File.join(@vroot, '.thumbs')) 99 | FileUtils.touch pjkh_thumb 100 | FileUtils.touch elfinder_thumb 101 | 102 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 103 | h, r = @elfinder.run(:cmd => 'rm', :targets => r[:cdc].select{|e| e[:mime] =~ /image/}.map{|e| e[:hash]}) 104 | 105 | assert !File.exist?(pjkh_thumb) 106 | assert !File.exist?(elfinder_thumb) 107 | end 108 | 109 | def test_thumbnail_removal_not_attempted_when_thumbs_not_enabled_and_image_removed 110 | @elfinder.options = { :thumbs => false } 111 | pjkh_thumb = File.join(@vroot, '.thumbs', "#{@elfinder.to_hash(ElFinder::Pathname.new(@vroot, 'pjkh.png'))}.png") 112 | elfinder_thumb = File.join(@vroot, '.thumbs', "#{@elfinder.to_hash(ElFinder::Pathname.new(@vroot, 'elfinder.png'))}.png") 113 | Dir.mkdir(File.join(@vroot, '.thumbs')) 114 | FileUtils.touch pjkh_thumb 115 | FileUtils.touch elfinder_thumb 116 | 117 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 118 | h, r = @elfinder.run(:cmd => 'rm', :targets => r[:cdc].select{|e| e[:mime] =~ /image/}.map{|e| e[:hash]}) 119 | 120 | assert_nil r[:error] 121 | end 122 | 123 | def test_open_response_contains_tmb_details_if_thumbs_exist 124 | @elfinder.options = { :thumbs => true } 125 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 126 | 127 | r[:cdc].select{|e| e[:mime] =~ /image/}.each do |img| 128 | assert_nil img[:tmb] 129 | end 130 | 131 | h, r = @elfinder.run(:cmd => 'tmb', :current => '') 132 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 133 | 134 | r[:cdc].select{|e| e[:mime] =~ /image/}.each do |img| 135 | assert_not_nil img[:tmb] 136 | end 137 | 138 | end 139 | 140 | 141 | 142 | ################################################################################ 143 | 144 | 145 | end 146 | -------------------------------------------------------------------------------- /test/test_el_finder.rb: -------------------------------------------------------------------------------- 1 | require 'el_finder_test_case' 2 | 3 | class TestElFinder < Test::Unit::TestCase 4 | 5 | include ElFinderTestCase 6 | 7 | ################################################################################ 8 | 9 | def test_should_fail_initialization_if_required_options_not_passed 10 | assert_raise RuntimeError do 11 | ElFinder::Connector.new() 12 | end 13 | end 14 | 15 | def test_should_fail_initialization_if_no_root_specified 16 | assert_raise RuntimeError do 17 | ElFinder::Connector.new({:url => '/elfinder'}) 18 | end 19 | end 20 | 21 | def test_should_fail_initialization_if_no_url_specified 22 | assert_raise RuntimeError do 23 | ElFinder::Connector.new({:root => '/tmp/elfinder'}) 24 | end 25 | end 26 | 27 | def test_should_fail_initialization_if_mime_handler_is_invalid 28 | assert_raise RuntimeError do 29 | ElFinder::Connector.new({:root => '/tmp/elfinder', :url => '/elfinder', :mime_handler => Object}) 30 | end 31 | end 32 | 33 | ################################################################################ 34 | 35 | def test_should_return_two_hashes 36 | h, r = @elfinder.run({}) 37 | assert_instance_of Hash, h 38 | assert_instance_of Hash, r 39 | end 40 | 41 | 42 | def test_should_return_invalid_request_if_command_is_invalid 43 | h, r = @elfinder.run({:cmd => 'INVALID'}) 44 | assert_not_nil r[:error] 45 | assert_match(/invalid command/i, r[:error]) 46 | end 47 | 48 | ################################################################################ 49 | 50 | def test_init_via_open 51 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 52 | assert_not_nil r[:cwd] 53 | assert_not_nil r[:cdc] 54 | assert_not_nil r[:disabled] 55 | assert_not_nil r[:params] 56 | r[:cdc].each do |e| 57 | case e[:name] 58 | when 'foo' 59 | assert_nil e[:dim] 60 | assert_nil e[:resize] 61 | assert_equal 'directory', e[:mime] 62 | assert_equal 0, e[:size] 63 | when 'pjkh.png' 64 | assert_equal '100x100', e[:dim] 65 | assert e[:resize] 66 | assert_equal 'image/png', e[:mime] 67 | assert_equal 1142, e[:size] 68 | end 69 | end 70 | end 71 | 72 | def test_cdc_is_sorted 73 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 74 | assert_equal 'elfinder.png', r[:cdc].first[:name] 75 | assert_equal 'sample.zip', r[:cdc].last[:name] 76 | end 77 | 78 | def test_cwd_name_for_root 79 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 80 | assert r[:cwd][:name], 'Home' 81 | end 82 | 83 | def test_cwd_name_for_sub_directory 84 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 85 | target = r[:cdc].find{|e| e[:name] == 'foo'} 86 | h, r = @elfinder.run(:cmd => 'open', :target => target[:hash]) 87 | assert r[:cwd][:name], 'Home/foo' 88 | end 89 | 90 | def test_mkdir 91 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 92 | h1, r1 = @elfinder.run(:cmd => 'mkdir', :current => r[:cwd][:hash], :name => 'dir1') 93 | assert File.directory?(File.join(@vroot, 'dir1')) 94 | assert_not_nil r1[:select] 95 | 96 | h1, r1 = @elfinder.run(:cmd => 'mkdir', :current => r[:cwd][:hash], :name => 'dir1') 97 | assert_match(/unable/i, r1[:error]) 98 | 99 | h1, r1 = @elfinder.run(:cmd => 'mkdir', :current => r[:cwd][:hash], :name => 'foo') 100 | assert_match(/unable/i, r1[:error]) 101 | end 102 | 103 | def test_mkfile 104 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 105 | h1, r1 = @elfinder.run(:cmd => 'mkfile', :current => r[:cwd][:hash], :name => 'file1') 106 | assert File.file?(File.join(@vroot, 'file1')) 107 | assert_not_nil r1[:select] 108 | 109 | h1, r1 = @elfinder.run(:cmd => 'mkfile', :current => r[:cwd][:hash], :name => 'file1') 110 | assert_match(/unable/i, r1[:error]) 111 | 112 | h1, r1 = @elfinder.run(:cmd => 'mkfile', :current => r[:cwd][:hash], :name => 'README.txt') 113 | assert_match(/unable/i, r1[:error]) 114 | end 115 | 116 | def test_rename_ok 117 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 118 | target = r[:cdc].find{|e| e[:name] == 'README.txt'} 119 | h1, r1 = @elfinder.run(:cmd => 'rename', :target => target[:hash], :current => r[:cwd][:hash], :name => 'file1') 120 | assert File.file?(File.join(@vroot, 'file1')) 121 | assert_not_nil r1[:select] 122 | end 123 | 124 | def test_rename_fail 125 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 126 | target = r[:cdc].find{|e| e[:name] == 'README.txt'} 127 | h1, r1 = @elfinder.run(:cmd => 'rename', :target => target[:hash], :current => r[:cwd][:hash], :name => 'foo') 128 | assert_match(/unable.*already exists/i, r1[:error]) 129 | assert File.file?(File.join(@vroot, 'README.txt')) 130 | assert_nil r1[:select] 131 | end 132 | 133 | def test_upload 134 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 135 | uploads = [] 136 | uploads << File.open(File.join(@vroot, 'foo/philip.txt')) 137 | uploads << File.open(File.join(@vroot, 'foo/sandy.txt')) 138 | h, r = @elfinder.run(:cmd => 'upload', :upload => uploads, :current => r[:cwd][:hash]) 139 | assert File.exist?(File.join(@vroot, 'philip.txt')) 140 | assert File.exist?(File.join(@vroot, 'sandy.txt')) 141 | assert_not_nil r[:select] 142 | end 143 | 144 | def test_ping 145 | h, r = @elfinder.run(:cmd => 'ping') 146 | assert r.empty? 147 | assert_equal 'Close', h['Connection'] 148 | end 149 | 150 | def test_paste_copy 151 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 152 | targets = r[:cdc].select{|e| e[:mime] != 'directory'} 153 | dst = r[:cdc].find{|e| e[:name] == 'foo'} 154 | 155 | h, r = @elfinder.run(:cmd => 'paste', :targets => targets.map{|e| e[:hash]}, :dst => dst[:hash]) 156 | assert_not_nil r[:tree] 157 | assert File.exist?(File.join(@vroot, 'README.txt')) 158 | assert File.exist?(File.join(@vroot, 'pjkh.png')) 159 | assert File.exist?(File.join(@vroot, 'elfinder.png')) 160 | assert File.exist?(File.join(@vroot, 'foo', 'README.txt')) 161 | assert File.exist?(File.join(@vroot, 'foo', 'pjkh.png')) 162 | assert File.exist?(File.join(@vroot, 'foo', 'elfinder.png')) 163 | end 164 | 165 | def test_paste_cut 166 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 167 | targets = r[:cdc].select{|e| e[:mime] != 'directory'} 168 | dst = r[:cdc].find{|e| e[:name] == 'foo'} 169 | 170 | h, r = @elfinder.run(:cmd => 'paste', :targets => targets.map{|e| e[:hash]}, :dst => dst[:hash], :cut => '1') 171 | assert_not_nil r[:tree] 172 | assert !File.exist?(File.join(@vroot, 'README.txt')) 173 | assert !File.exist?(File.join(@vroot, 'pjkh.png')) 174 | assert !File.exist?(File.join(@vroot, 'elfinder.png')) 175 | assert File.exist?(File.join(@vroot, 'foo', 'README.txt')) 176 | assert File.exist?(File.join(@vroot, 'foo', 'pjkh.png')) 177 | assert File.exist?(File.join(@vroot, 'foo', 'elfinder.png')) 178 | end 179 | 180 | def test_paste_partial_failure 181 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 182 | h, r = @elfinder.run(:cmd => 'mkfile', :current => r[:cwd][:hash], :name => 'philip.txt') 183 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 184 | 185 | targets = r[:cdc].select{|e| e[:mime] != 'directory'} 186 | dst = r[:cdc].find{|e| e[:name] == 'foo'} 187 | 188 | h, r = @elfinder.run(:cmd => 'paste', :targets => targets.map{|e| e[:hash]}, :dst => dst[:hash]) 189 | assert_not_nil r[:tree] 190 | assert_match(/unable to be copied/i, r[:error]) 191 | assert_not_nil r[:errorData] 192 | assert_equal 1, r[:errorData].size 193 | assert File.exist?(File.join(@vroot, 'philip.txt')) 194 | assert File.exist?(File.join(@vroot, 'foo', 'philip.txt')) 195 | assert File.exist?(File.join(@vroot, 'foo', 'README.txt')) 196 | assert File.exist?(File.join(@vroot, 'foo', 'pjkh.png')) 197 | assert File.exist?(File.join(@vroot, 'foo', 'elfinder.png')) 198 | end 199 | 200 | def test_rm 201 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 202 | h, r1 = @elfinder.run(:cmd => 'rm', :current => r[:cwd][:hash], :targets => []) 203 | assert_match(/no files/i, r1[:error]) 204 | 205 | h, r = @elfinder.run(:cmd => 'rm', :targets => r[:cdc].reject{|e| e[:mime] =~ /image/}.map{|e| e[:hash]}) 206 | assert !File.exist?(File.join(@vroot, 'README.txt')) 207 | assert File.exist?(File.join(@vroot, 'pjkh.png')) 208 | assert File.exist?(File.join(@vroot, 'elfinder.png')) 209 | assert !File.exist?(File.join(@vroot, 'foo')) 210 | end 211 | 212 | def test_duplicate 213 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 214 | duplicate = r[:cdc].find{|e| e[:name] == 'README.txt'} 215 | assert File.exist?(File.join(@vroot, 'README.txt')) 216 | h, r = @elfinder.run(:cmd => 'duplicate', :target => duplicate[:hash]) 217 | assert File.exist?(File.join(@vroot, 'README copy 1.txt')) 218 | assert_not_nil r[:select] 219 | h, r = @elfinder.run(:cmd => 'duplicate', :target => duplicate[:hash]) 220 | assert File.exist?(File.join(@vroot, 'README copy 2.txt')) 221 | end 222 | 223 | def test_read 224 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 225 | file = r[:cdc].find{|e| e[:name] == 'README.txt'} 226 | h, r = @elfinder.run(:cmd => 'read', :target => file[:hash]) 227 | assert_equal r[:content], File.read(File.join(@vroot, 'README.txt')) 228 | end 229 | 230 | def test_edit 231 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 232 | file = r[:cdc].find{|e| e[:name] == 'README.txt'} 233 | h, r = @elfinder.run(:cmd => 'edit', :target => file[:hash], :content => 'Hello') 234 | assert_equal 'Hello', File.read(File.join(@vroot, 'README.txt')) 235 | assert_not_nil r[:file] 236 | end 237 | 238 | def test_resize 239 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 240 | file = r[:cdc].find{|e| e[:name] == 'pjkh.png'} 241 | h, r = @elfinder.run(:cmd => 'resize', :target => file[:hash], :current => r[:cwd][:hash], :width => '50', :height => '25') 242 | assert File.exist?(File.join(@vroot, 'pjkh.png')) 243 | assert_equal '50x25', ElFinder::Image.size(File.join(@vroot, 'pjkh.png')).to_s 244 | end 245 | 246 | ################################################################################ 247 | 248 | end 249 | -------------------------------------------------------------------------------- /test/el_finder/test_pathname.rb: -------------------------------------------------------------------------------- 1 | require 'test/unit' 2 | require 'el_finder' 3 | require 'fileutils' 4 | require 'pp' 5 | 6 | class TestPathname < Test::Unit::TestCase 7 | 8 | def setup 9 | @vroot = '/tmp/elfinder' 10 | FileUtils.mkdir_p(@vroot) 11 | FileUtils.cp_r "#{File.dirname(__FILE__)}/../files/.", @vroot 12 | end 13 | 14 | def teardown 15 | FileUtils.rm_rf(@vroot) 16 | end 17 | 18 | ################################################################################ 19 | 20 | def test_new_fails_without_root 21 | assert_raise ArgumentError do 22 | ElFinder::Pathname.new() 23 | end 24 | end 25 | 26 | def test_new_okay_with_root 27 | assert_nothing_raised do 28 | ElFinder::Pathname.new(@vroot) 29 | end 30 | end 31 | 32 | def test_new_okay_with_root_and_path 33 | assert_nothing_raised do 34 | ElFinder::Pathname.new(@vroot, 'foo.txt') 35 | end 36 | end 37 | 38 | def test_instance_variables_are_set_correctly 39 | p = ElFinder::Pathname.new(@vroot, 'foo.txt') 40 | assert_equal @vroot, p.root.to_s 41 | assert_equal 'foo.txt', p.path.to_s 42 | end 43 | 44 | def test_instance_variables_are_set_correctly_with_nil_path 45 | p = ElFinder::Pathname.new(@vroot) 46 | assert_equal @vroot, p.root.to_s 47 | assert_equal '.', p.path.to_s 48 | end 49 | 50 | def test_instance_variables_are_kind_of_pathname 51 | p = ElFinder::Pathname.new(@vroot, 'foo.txt') 52 | assert_kind_of ::Pathname, p.root 53 | assert_kind_of ::Pathname, p.path 54 | end 55 | 56 | def test_attempt_to_break_out_of_root_using_relative_path 57 | assert_raise SecurityError do 58 | p = ElFinder::Pathname.new(@vroot, '../foo.txt') 59 | end 60 | end 61 | 62 | def test_attempt_to_break_out_of_root_using_absolute_path 63 | assert_raise SecurityError do 64 | p = ElFinder::Pathname.new(@vroot, '/foo.txt') 65 | end 66 | end 67 | 68 | def test_new_with_full_path_matching_root 69 | p = ElFinder::Pathname.new(@vroot, "#{@vroot}/foo.txt") 70 | assert_equal 'foo.txt', p.path.to_s 71 | end 72 | 73 | def test_new_with_full_path_matching_root_realpath 74 | p = ElFinder::Pathname.new(@vroot, "#{Pathname.new(@vroot).realpath.to_s}/foo.txt") 75 | assert_equal 'foo.txt', p.path.to_s 76 | end 77 | 78 | def test_plus_string 79 | p = ElFinder::Pathname.new(@vroot, 'foo') 80 | p1 = p + 'bar' 81 | assert_equal 'foo/bar', p1.path.to_s 82 | end 83 | 84 | def test_plus_pathname 85 | p = ElFinder::Pathname.new(@vroot, 'foo') 86 | p1 = p + Pathname.new('bar') 87 | assert_equal 'foo/bar', p1.path.to_s 88 | end 89 | 90 | def test_plus_elfinder_pathname 91 | p = ElFinder::Pathname.new(@vroot, 'foo') 92 | p1 = p + ElFinder::Pathname.new(@vroot, 'bar') 93 | assert_equal 'foo/bar', p1.path.to_s 94 | end 95 | 96 | def test_fullpath 97 | assert_equal "#{@vroot}/one/two/three.txt", ElFinder::Pathname.new(@vroot, 'one/two/three.txt').fullpath.to_s 98 | end 99 | 100 | def test_file? 101 | assert_equal true, ElFinder::Pathname.new(@vroot, 'README.txt').file?, "README.txt should be a file" 102 | assert_equal false, ElFinder::Pathname.new(@vroot, 'INVALID').file?, "INVALID should not be a file" 103 | assert_equal false, ElFinder::Pathname.new(@vroot, 'foo').file?, "foo should not be a file (it's a directory)" 104 | end 105 | 106 | def test_directory? 107 | assert_equal true, ElFinder::Pathname.new(@vroot, 'foo').directory?, "foo should be a directory" 108 | assert_equal false, ElFinder::Pathname.new(@vroot, 'README.txt').directory?, "README.txt should not be a directory (it's a file)" 109 | assert_equal false, ElFinder::Pathname.new(@vroot, 'INVALID').directory?, "INVALID should not be a directory" 110 | end 111 | 112 | def test_exist? 113 | assert_equal true, ElFinder::Pathname.new(@vroot, 'foo').exist?, "foo should exist" 114 | assert_equal true, ElFinder::Pathname.new(@vroot, 'README.txt').exist?, "README.txt should exist" 115 | assert_equal false, ElFinder::Pathname.new(@vroot, 'INVALID').exist?, "INVALID should not exist" 116 | end 117 | 118 | def test_symlink? 119 | File.symlink(File.join(@vroot, 'README.txt'), File.join(@vroot, 'symlink.txt')) 120 | assert_equal true, ElFinder::Pathname.new(@vroot, 'symlink.txt').symlink?, "symlink.txt should be a symlink" 121 | assert_equal false, ElFinder::Pathname.new(@vroot, 'README.txt').symlink?, "README.txt should not be a symlink" 122 | end 123 | 124 | def test_readable? 125 | assert_equal true, ElFinder::Pathname.new(@vroot, 'foo').readable?, "foo should be readable" 126 | assert_equal true, ElFinder::Pathname.new(@vroot, 'README.txt').readable?, "README.txt should be readable" 127 | assert_equal false, ElFinder::Pathname.new(@vroot, 'INVALID').readable?, "INVALID should not be readable" 128 | end 129 | 130 | def test_writable? 131 | assert_equal true, ElFinder::Pathname.new(@vroot, 'foo').writable?, "foo should be writable" 132 | assert_equal true, ElFinder::Pathname.new(@vroot, 'README.txt').writable?, "README.txt should be writable" 133 | assert_equal false, ElFinder::Pathname.new(@vroot, 'INVALID').writable?, "INVALID should not be writable" 134 | end 135 | 136 | def test_mtime 137 | assert_equal File.new(File.join(@vroot, 'foo')).mtime, ElFinder::Pathname.new(@vroot, 'foo').mtime 138 | assert_equal File.new(File.join(@vroot, 'README.txt')).mtime, ElFinder::Pathname.new(@vroot, 'README.txt').mtime 139 | assert_raise Errno::ENOENT do 140 | ElFinder::Pathname.new(@vroot, 'INVALID').mtime 141 | end 142 | end 143 | 144 | def test_unlink 145 | assert_equal true, ElFinder::Pathname.new(@vroot, 'README.txt').exist? 146 | ElFinder::Pathname.new(@vroot, 'README.txt').unlink 147 | assert_equal false, ElFinder::Pathname.new(@vroot, 'README.txt').exist? 148 | assert_raise Errno::ENOENT do 149 | ElFinder::Pathname.new(@vroot, 'INVALID').unlink 150 | end 151 | assert_raise Errno::ENOTEMPTY do 152 | ElFinder::Pathname.new(@vroot, 'foo').unlink 153 | end 154 | end 155 | 156 | def test_basename 157 | assert_equal 'README.txt', ElFinder::Pathname.new(@vroot, 'README.txt').basename.to_s 158 | assert_equal 'README', ElFinder::Pathname.new(@vroot, 'README.txt').basename('.txt').to_s 159 | assert_equal 'tom.txt', ElFinder::Pathname.new(@vroot, 'foo/tom.txt').basename.to_s 160 | end 161 | 162 | def test_basename_sans_extension 163 | assert_equal 'README', ElFinder::Pathname.new(@vroot, 'README.txt').basename_sans_extension.to_s 164 | assert_equal 'tom', ElFinder::Pathname.new(@vroot, 'foo/tom.txt').basename_sans_extension.to_s 165 | end 166 | 167 | def test_dirname 168 | assert_equal '.', ElFinder::Pathname.new(@vroot, 'README.txt').dirname.path.to_s 169 | assert_equal 'foo', ElFinder::Pathname.new(@vroot, 'foo/tom.txt').dirname.path.to_s 170 | end 171 | 172 | def test_to_s 173 | assert_equal "#{@vroot}/README.txt", ElFinder::Pathname.new(@vroot, 'README.txt').to_s 174 | assert_equal "#{@vroot}/foo/tom.txt", ElFinder::Pathname.new(@vroot, 'foo/tom.txt').to_s 175 | end 176 | 177 | def test_children 178 | children = ElFinder::Pathname.new(@vroot, 'foo').children 179 | assert_equal 4, children.size 180 | assert_equal %w[philip sam sandy tom], children.map{|e| e.basename_sans_extension.to_s}.sort 181 | end 182 | 183 | def test_mkdir 184 | p = ElFinder::Pathname.new(@vroot, 'some-dir') 185 | assert_equal false, p.directory? 186 | p.mkdir 187 | assert_equal true, p.directory? 188 | end 189 | 190 | def test_read 191 | p = ElFinder::Pathname.new(@vroot, 'foo/philip.txt') 192 | assert_equal File.read(File.join(@vroot, 'foo/philip.txt')), p.read 193 | end 194 | 195 | def test_touch 196 | p = ElFinder::Pathname.new(@vroot, 'newfile') 197 | p.touch 198 | assert_equal true, p.file? 199 | end 200 | 201 | def test_open 202 | p = ElFinder::Pathname.new(@vroot, 'newfile') 203 | assert_equal false, p.file? 204 | p.open('w') {|f| f.puts "new"} 205 | assert_equal true, p.file? 206 | assert_equal File.read(File.join(@vroot, 'newfile')), p.read 207 | end 208 | 209 | def test_unique_on_create 210 | file = ElFinder::Pathname.new(@vroot, 'foo.txt') 211 | assert_equal 'foo.txt', file.unique.basename.to_s 212 | end 213 | 214 | def test_unique_conflict 215 | file = ElFinder::Pathname.new(@vroot, 'pjkh.png') 216 | assert_equal 'pjkh 1.png', file.unique.basename.to_s 217 | end 218 | 219 | def test_unique_conflict_twice 220 | ElFinder::Pathname.new(@vroot, 'pjkh 1.png').touch 221 | file = ElFinder::Pathname.new(@vroot, 'pjkh.png') 222 | assert_equal 'pjkh 2.png', file.unique.basename.to_s 223 | end 224 | 225 | 226 | def test_duplication_without_extension 227 | assert_equal File.join(@vroot, 'README copy 1'), ElFinder::Pathname.new(@vroot,'README').duplicate.fullpath.to_s 228 | end 229 | 230 | def test_2nd_duplication_without_extension 231 | ::FileUtils.touch(File.join(@vroot, 'README copy 1')) 232 | assert_equal File.join(@vroot, 'README copy 2'), ElFinder::Pathname.new(@vroot,'README').duplicate.fullpath.to_s 233 | end 234 | 235 | def test_duplication_with_extension 236 | assert_equal File.join(@vroot, 'README copy 1.txt'), ElFinder::Pathname.new(@vroot,'README.txt').duplicate.fullpath.to_s 237 | end 238 | 239 | def test_2nd_duplication_with_extension 240 | ::FileUtils.touch(File.join(@vroot, 'README copy 1.txt')) 241 | assert_equal File.join(@vroot, 'README copy 2.txt'), ElFinder::Pathname.new(@vroot,'README.txt').duplicate.fullpath.to_s 242 | end 243 | 244 | def test_duplication_of_duplication_lookalike 245 | assert_equal File.join(@vroot, 'README copy A copy 1.txt'), ElFinder::Pathname.new(@vroot,'README copy A.txt').duplicate.fullpath.to_s 246 | end 247 | 248 | def test_duplication_of_duplication_lookalike2 249 | assert_equal File.join(@vroot, 'README copy copy 1.txt'), ElFinder::Pathname.new(@vroot,'README copy.txt').duplicate.fullpath.to_s 250 | end 251 | 252 | def test_on_disk_duplication 253 | file = ElFinder::Pathname.new(@vroot, 'README.txt') 254 | file.touch 255 | assert_equal true, File.exist?(File.join(@vroot, 'README.txt')) 256 | duplicate = file.duplicate 257 | duplicate.touch 258 | assert_equal true, File.exist?(File.join(@vroot, 'README copy 1.txt')) 259 | end 260 | 261 | def test_rename_on_same_filesystem 262 | file = ElFinder::Pathname.new(@vroot, 'old.txt') 263 | file.touch 264 | assert_equal true, File.exist?(File.join(@vroot, 'old.txt')) 265 | file.rename(File.join(@vroot, 'new.txt')) 266 | assert_equal false, File.exist?(File.join(@vroot, 'old.txt')) 267 | assert_equal true, File.exist?(File.join(@vroot, 'new.txt')) 268 | assert_equal 'new.txt', file.path.to_s 269 | end 270 | 271 | def test_rename_on_different_filesystem 272 | if File.directory?('/Volumes/MyBook') 273 | file = ElFinder::Pathname.new(@vroot, 'old.txt') 274 | file.touch 275 | assert_equal true, File.exist?(File.join(@vroot, 'old.txt')) 276 | 277 | File.symlink('/Volumes/MyBook', File.join(@vroot, 'mybook')) 278 | assert_equal true, File.symlink?(File.join(@vroot, 'mybook')) 279 | assert_equal '/Volumes/MyBook', File.readlink(File.join(@vroot, 'mybook')) 280 | 281 | file.rename('mybook/elfinder.rename.test.safe.to.delete') 282 | assert_equal false, File.exist?(File.join(@vroot, 'old.txt')) 283 | assert_equal true, File.exist?('/Volumes/MyBook/elfinder.rename.test.safe.to.delete') 284 | file.unlink 285 | assert_equal false, File.exist?('/Volumes/MyBook/elfinder.rename.test.safe.to.delete') 286 | end 287 | end 288 | 289 | end 290 | -------------------------------------------------------------------------------- /test/test_el_finder_permissions.rb: -------------------------------------------------------------------------------- 1 | require 'el_finder_test_case' 2 | 3 | class TestElFinder < Test::Unit::TestCase 4 | 5 | include ElFinderTestCase 6 | 7 | ################################################################################ 8 | 9 | def test_default_permissions 10 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 11 | 12 | assert_equal true, r[:cwd][:read] 13 | assert_equal true, r[:cwd][:write] 14 | assert_equal false, r[:cwd][:rm] 15 | 16 | r[:cdc].each do |e| 17 | assert_equal true, e[:read] 18 | assert_equal true, e[:write] 19 | assert_equal true, e[:rm] 20 | end 21 | end 22 | 23 | def test_custom_permissions_on_root 24 | @elfinder.options = { 25 | :perms => { 26 | '.' => {:read => false}, 27 | } 28 | } 29 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 30 | assert_match(/access denied/i, r[:error]) 31 | end 32 | 33 | def test_custom_permissions 34 | @elfinder.options = { 35 | :perms => { 36 | 'foo' => {:rm => false}, 37 | /.*.png$/ => {:rm => false}, 38 | /^pjkh/ => {:read => false}, 39 | 'README.txt' => {:write => false}, 40 | } 41 | } 42 | 43 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 44 | 45 | r[:cdc].each do |e| 46 | case e[:name] 47 | when 'elfinder.png' 48 | assert_equal true, e[:read] 49 | assert_equal true, e[:write] 50 | assert_equal false, e[:rm] 51 | when 'foo' 52 | assert_equal true, e[:read] 53 | assert_equal true, e[:write] 54 | assert_equal false, e[:rm] 55 | when 'pjkh.png' 56 | assert_equal false, e[:read] 57 | assert_equal true, e[:write] 58 | assert_equal false, e[:rm] 59 | when 'README.txt' 60 | assert_equal true, e[:read] 61 | assert_equal false, e[:write] 62 | assert_equal true, e[:rm] 63 | end 64 | end 65 | end 66 | 67 | def test_custom_permissions_multiple_matches_prefers_false 68 | @elfinder.options = { 69 | :perms => { 70 | 'pjkh.png' => {:read => false}, 71 | /pjkh/ => {:read => true}, 72 | } 73 | } 74 | 75 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 76 | 77 | r[:cdc].each do |e| 78 | case e[:name] 79 | when 'pjkh.png' 80 | assert_equal false, e[:read] 81 | assert_equal true, e[:write] 82 | assert_equal true, e[:rm] 83 | else 84 | assert_equal true, e[:read] 85 | assert_equal true, e[:write] 86 | assert_equal true, e[:rm] 87 | end 88 | end 89 | end 90 | 91 | def test_custom_permissions_in_subdirectories 92 | @elfinder.options = { 93 | :perms => { 94 | %r{foo/s.*} => {:read => false} 95 | } 96 | } 97 | 98 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 99 | h, r = @elfinder.run(:cmd => 'open', :target => r[:cdc].find{|e| e[:name] == 'foo'}[:hash]) 100 | 101 | r[:cdc].each do |e| 102 | case e[:name] 103 | when 'sandy.txt', 'sam.txt' 104 | assert_equal false, e[:read] 105 | else 106 | assert_equal true, e[:read] 107 | end 108 | end 109 | end 110 | 111 | def test_open_permissions 112 | @elfinder.options = { 113 | :perms => { 114 | 'foo' => {:read => false} 115 | } 116 | } 117 | 118 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 119 | target = r[:cdc].find{|e| e[:name] == 'foo'} 120 | h1, r = @elfinder.run(:cmd => 'open', :target => target[:hash]) 121 | assert_match(/access denied/i, r[:error]) 122 | end 123 | 124 | def test_mkdir_permissions 125 | @elfinder.options = { 126 | :perms => { 127 | 'foo' => {:write => false} 128 | } 129 | } 130 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 131 | target = r[:cdc].find{|e| e[:name] == 'foo'} 132 | h1, r = @elfinder.run(:cmd => 'open', :target => target[:hash]) 133 | 134 | h, r = @elfinder.run(:cmd => 'mkdir', :current => r[:cwd][:hash], :name => 'dir1') 135 | assert !File.directory?(File.join(@vroot, 'foo', 'dir1')) 136 | assert_nil r[:select] 137 | assert_match(/access denied/i, r[:error]) 138 | end 139 | 140 | def test_mkfile_permissions 141 | @elfinder.options = { 142 | :perms => { 143 | 'foo' => {:write => false} 144 | } 145 | } 146 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 147 | target = r[:cdc].find{|e| e[:name] == 'foo'} 148 | h1, r = @elfinder.run(:cmd => 'open', :target => target[:hash]) 149 | 150 | h, r = @elfinder.run(:cmd => 'mkfile', :current => r[:cwd][:hash], :name => 'file1') 151 | assert !File.file?(File.join(@vroot, 'foo', 'file1')) 152 | assert_nil r[:select] 153 | assert_match(/access denied/i, r[:error]) 154 | end 155 | 156 | def test_rename_permissions_file_rm_false 157 | @elfinder.options = { 158 | :perms => { 159 | 'README.txt' => {:rm => false} 160 | } 161 | } 162 | 163 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 164 | target = r[:cdc].find{|e| e[:name] == 'README.txt'} 165 | h1, r = @elfinder.run(:cmd => 'rename', :target => target[:hash], :current => r[:cwd][:hash], :name => 'file1') 166 | assert File.file?(File.join(@vroot, 'README.txt')) 167 | assert !File.file?(File.join(@vroot, 'file1')) 168 | assert_nil r[:select] 169 | assert_match(/access denied/i, r[:error]) 170 | end 171 | 172 | def test_rename_permissions_dir_write_false 173 | @elfinder.options = { 174 | :perms => { 175 | '.' => {:write => false} 176 | } 177 | } 178 | 179 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 180 | target = r[:cdc].find{|e| e[:name] == 'README.txt'} 181 | h1, r = @elfinder.run(:cmd => 'rename', :target => target[:hash], :current => r[:cwd][:hash], :name => 'file1') 182 | assert File.file?(File.join(@vroot, 'README.txt')) 183 | assert !File.file?(File.join(@vroot, 'file1')) 184 | assert_nil r[:select] 185 | assert_match(/access denied/i, r[:error]) 186 | end 187 | 188 | def test_upload_permissions 189 | @elfinder.options = { 190 | :perms => { 191 | '.' => {:write => false} 192 | } 193 | } 194 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 195 | uploads = [] 196 | uploads << File.open(File.join(@vroot, 'foo/philip.txt')) 197 | h, r = @elfinder.run(:cmd => 'upload', :upload => uploads, :current => r[:cwd][:hash]) 198 | assert !File.exist?(File.join(@vroot, 'philip.txt')) 199 | assert_nil r[:select] 200 | assert_match(/access denied/i, r[:error]) 201 | end 202 | 203 | def test_paste_permissions_on_dst 204 | @elfinder.options = { 205 | :perms => { 206 | 'foo' => {:write => false} 207 | } 208 | } 209 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 210 | targets = r[:cdc].select{|e| e[:mime] != 'directory'} 211 | dst = r[:cdc].find{|e| e[:name] == 'foo'} 212 | 213 | h, r = @elfinder.run(:cmd => 'paste', :targets => targets.map{|e| e[:hash]}, :dst => dst[:hash]) 214 | assert_match(/access denied/i, r[:error]) 215 | assert !File.exist?(File.join(@vroot, 'foo', 'README.txt')) 216 | assert !File.exist?(File.join(@vroot, 'foo', 'pjkh.png')) 217 | assert !File.exist?(File.join(@vroot, 'foo', 'elfinder.png')) 218 | end 219 | 220 | def test_paste_permissions_on_target 221 | @elfinder.options = { 222 | :perms => { 223 | 'README.txt' => {:read => false} 224 | } 225 | } 226 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 227 | targets = r[:cdc].select{|e| e[:mime] != 'directory'} 228 | dst = r[:cdc].find{|e| e[:name] == 'foo'} 229 | 230 | h, r = @elfinder.run(:cmd => 'paste', :targets => targets.map{|e| e[:hash]}, :dst => dst[:hash]) 231 | assert !File.exist?(File.join(@vroot, 'foo', 'README.txt')) 232 | assert File.exist?(File.join(@vroot, 'foo', 'pjkh.png')) 233 | assert File.exist?(File.join(@vroot, 'foo', 'elfinder.png')) 234 | end 235 | 236 | def test_rm_permissions_file_rm_false 237 | @elfinder.options = { 238 | :perms => { 239 | /.*\.png/ => {:rm => false} 240 | } 241 | } 242 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 243 | h, r = @elfinder.run(:cmd => 'rm', :targets => r[:cdc].map{|e| e[:hash]}) 244 | 245 | assert !File.exist?(File.join(@vroot, 'README.txt')) 246 | assert File.exist?(File.join(@vroot, 'pjkh.png')) 247 | assert File.exist?(File.join(@vroot, 'elfinder.png')) 248 | assert !File.exist?(File.join(@vroot, 'foo')) 249 | 250 | assert_match(/unable to be removed/i, r[:error]) 251 | assert_match(/access denied/i, r[:errorData].to_s) 252 | end 253 | 254 | def test_rm_permissions_chmod_perm_hack 255 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 256 | File.unlink(File.join(@vroot, 'pjkh.png')) 257 | h, r = @elfinder.run(:cmd => 'rm', :targets => r[:cdc].map{|e| e[:hash]}) 258 | 259 | assert_match(/unable to be removed/i, r[:error]) 260 | assert_match(/pjkh.png.*remove failed/i, r[:errorData].to_s) 261 | end 262 | 263 | def test_duplicate_permissions_file 264 | @elfinder.options = { 265 | :perms => { 266 | 'README.txt' => {:read => false} 267 | } 268 | } 269 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 270 | duplicate = r[:cdc].find{|e| e[:name] == 'README.txt'} 271 | h, r = @elfinder.run(:cmd => 'duplicate', :target => duplicate[:hash]) 272 | assert !File.exist?(File.join(@vroot, 'README copy 1.txt')) 273 | assert_match(/access denied/i, r[:error]) 274 | assert_match(/unable to read/i, r[:errorData].to_s) 275 | end 276 | 277 | def test_duplicate_permissions_directory 278 | @elfinder.options = { 279 | :perms => { 280 | '.' => {:write => false} 281 | } 282 | } 283 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 284 | duplicate = r[:cdc].find{|e| e[:name] == 'README.txt'} 285 | h, r = @elfinder.run(:cmd => 'duplicate', :target => duplicate[:hash]) 286 | assert !File.exist?(File.join(@vroot, 'README copy 1.txt')) 287 | assert_match(/access denied/i, r[:error]) 288 | assert_match(/unable to write/i, r[:errorData].to_s) 289 | end 290 | 291 | 292 | def test_read_file_permissions 293 | @elfinder.options = { 294 | :perms => { 295 | 'README.txt' => {:read => false} 296 | } 297 | } 298 | 299 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 300 | target = r[:cdc].find{|e| e[:name] == 'README.txt'} 301 | h, r = @elfinder.run(:cmd => 'read', :target => target[:hash]) 302 | 303 | assert_nil r[:content] 304 | assert_match(/access denied/i, r[:error]) 305 | end 306 | 307 | def test_edit_permissions_write 308 | @elfinder.options = { 309 | :perms => { 310 | 'README.txt' => {:write => false} 311 | } 312 | } 313 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 314 | file = r[:cdc].find{|e| e[:name] == 'README.txt'} 315 | h, r = @elfinder.run(:cmd => 'edit', :target => file[:hash], :content => 'Hello') 316 | assert_match(/access denied/i, r[:error]) 317 | assert_not_equal 'Hello', File.read(File.join(@vroot, 'README.txt')) 318 | end 319 | 320 | def test_edit_permissions_read 321 | @elfinder.options = { 322 | :perms => { 323 | 'README.txt' => {:read => false} 324 | } 325 | } 326 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 327 | file = r[:cdc].find{|e| e[:name] == 'README.txt'} 328 | h, r = @elfinder.run(:cmd => 'edit', :target => file[:hash], :content => 'Hello') 329 | assert_match(/access denied/i, r[:error]) 330 | assert_not_equal 'Hello', File.read(File.join(@vroot, 'README.txt')) 331 | end 332 | 333 | def test_resize_permissions_write 334 | @elfinder.options = { 335 | :perms => { 336 | 'pjkh.png' => {:write => false} 337 | } 338 | } 339 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 340 | file = r[:cdc].find{|e| e[:name] == 'pjkh.png'} 341 | h, r = @elfinder.run(:cmd => 'resize', :target => file[:hash], :current => r[:cwd][:hash], :width => '50', :height => '25') 342 | assert_match(/access denied/i, r[:error]) 343 | assert File.exist?(File.join(@vroot, 'pjkh.png')) 344 | assert_equal '100x100', ElFinder::Image.size(File.join(@vroot, 'pjkh.png')).to_s 345 | end 346 | 347 | def test_resize_permissions_read 348 | @elfinder.options = { 349 | :perms => { 350 | 'pjkh.png' => {:read => false} 351 | } 352 | } 353 | h, r = @elfinder.run(:cmd => 'open', :init => 'true', :target => '') 354 | file = r[:cdc].find{|e| e[:name] == 'pjkh.png'} 355 | h, r = @elfinder.run(:cmd => 'resize', :target => file[:hash], :current => r[:cwd][:hash], :width => '50', :height => '25') 356 | assert_match(/access denied/i, r[:error]) 357 | assert File.exist?(File.join(@vroot, 'pjkh.png')) 358 | assert_equal '100x100', ElFinder::Image.size(File.join(@vroot, 'pjkh.png')).to_s 359 | end 360 | 361 | 362 | end 363 | -------------------------------------------------------------------------------- /lib/el_finder/connector.rb: -------------------------------------------------------------------------------- 1 | # 2 | # http://elrte.org/redmine/projects/elfinder/wiki/Client-Server_Protocol_EN 3 | # 4 | 5 | require 'base64' 6 | 7 | module ElFinder 8 | class Connector 9 | 10 | VALID_COMMANDS = %w[archive duplicate edit extract mkdir mkfile open paste ping read rename resize rm tmb upload] 11 | 12 | DEFAULT_OPTIONS = { 13 | :mime_handler => ElFinder::MimeType, 14 | :image_handler => ElFinder::Image, 15 | :original_filename_method => lambda {|file| file.original_filename}, 16 | :disabled_commands => [], 17 | :allow_dot_files => true, 18 | :upload_max_size => '50M', 19 | :upload_file_mode => 0644, 20 | :archivers => {}, 21 | :extractors => {}, 22 | :home => 'Home', 23 | :default_perms => {:read => true, :write => true, :rm => true}, 24 | :perms => [], 25 | :thumbs => false, 26 | :thumbs_directory => '.thumbs', 27 | :thumbs_size => 48, 28 | :thumbs_at_once => 5, 29 | } 30 | 31 | # 32 | def initialize(options = {}) 33 | @options = DEFAULT_OPTIONS.merge(options) 34 | 35 | raise(RuntimeError, "Missing required :url option") unless @options.key?(:url) 36 | raise(RuntimeError, "Missing required :root option") unless @options.key?(:root) 37 | raise(RuntimeError, "Mime Handler is invalid") unless mime_handler.respond_to?(:for) 38 | raise(RuntimeError, "Image Handler is invalid") unless image_handler.nil? || ([:size, :resize, :thumbnail].all?{|m| image_handler.respond_to?(m)}) 39 | 40 | @root = ElFinder::Pathname.new(options[:root]) 41 | 42 | @headers = {} 43 | @response = {} 44 | end # of initialize 45 | 46 | # 47 | def run(params = {}) 48 | @params = params.dup 49 | @headers = {} 50 | @response = {} 51 | @response[:errorData] = {} 52 | 53 | if VALID_COMMANDS.include?(@params[:cmd]) 54 | 55 | if @options[:thumbs] 56 | @thumb_directory = @root + @options[:thumbs_directory] 57 | @thumb_directory.mkdir unless @thumb_directory.exist? 58 | raise(RuntimeError, "Unable to create thumbs directory") unless @thumb_directory.directory? 59 | end 60 | 61 | @current = @params[:current] ? from_hash(@params[:current]) : nil 62 | @target = @params[:target] ? from_hash(@params[:target]) : nil 63 | if params[:targets] 64 | @targets = @params[:targets].map{|t| from_hash(t)} 65 | end 66 | 67 | send("_#{@params[:cmd]}") 68 | else 69 | invalid_request 70 | end 71 | 72 | @response.delete(:errorData) if @response[:errorData].empty? 73 | 74 | return @headers, @response 75 | end # of run 76 | 77 | # 78 | def to_hash(pathname) 79 | Base64.encode64(pathname.path.to_s).chomp.tr("\n", "_") 80 | end # of to_hash 81 | 82 | # 83 | def from_hash(hash) 84 | pathname = @root + Base64.decode64(hash.tr("_", "\n")) 85 | end # of from_hash 86 | 87 | # 88 | def options=(opts = {}) 89 | opts.each_pair do |k,v| 90 | @options[k.to_sym] = v 91 | end 92 | end 93 | 94 | ################################################################################ 95 | protected 96 | 97 | # 98 | def _open(target = nil) 99 | target ||= @target 100 | 101 | if target.nil? 102 | _open(@root) 103 | return 104 | end 105 | 106 | if perms_for(target)[:read] == false 107 | @response[:error] = 'Access Denied' 108 | return 109 | end 110 | 111 | if target.file? 112 | command_not_implemented 113 | elsif target.directory? 114 | @response[:cwd] = cwd_for(target) 115 | @response[:cdc] = target.children.sort_by{|e| e.basename.to_s.downcase}.map{|e| cdc_for(e)}.compact 116 | 117 | if @params[:tree] 118 | @response[:tree] = { 119 | :name => @options[:home], 120 | :hash => to_hash(@root), 121 | :dirs => tree_for(@root), 122 | }.merge(perms_for(@root)) 123 | end 124 | 125 | if @params[:init] 126 | @response[:disabled] = @options[:disabled_commands] 127 | @response[:params] = { 128 | :dotFiles => @options[:allow_dot_files], 129 | :uplMaxSize => @options[:upload_max_size], 130 | :archives => @options[:archivers].keys, 131 | :extract => @options[:extractors].keys, 132 | :url => @options[:url] 133 | } 134 | end 135 | 136 | else 137 | @response[:error] = "Directory does not exist" 138 | _open(@root) 139 | end 140 | 141 | end # of open 142 | 143 | # 144 | def _mkdir 145 | if perms_for(@current)[:write] == false 146 | @response[:error] = 'Access Denied' 147 | return 148 | end 149 | 150 | dir = @current + @params[:name] 151 | if !dir.exist? && dir.mkdir 152 | @params[:tree] = true 153 | @response[:select] = [to_hash(dir)] 154 | _open(@current) 155 | else 156 | @response[:error] = "Unable to create folder" 157 | end 158 | end # of mkdir 159 | 160 | # 161 | def _mkfile 162 | if perms_for(@current)[:write] == false 163 | @response[:error] = 'Access Denied' 164 | return 165 | end 166 | 167 | file = @current + @params[:name] 168 | if !file.exist? && file.touch 169 | @response[:select] = [to_hash(file)] 170 | _open(@current) 171 | else 172 | @response[:error] = "Unable to create file" 173 | end 174 | end # of mkfile 175 | 176 | # 177 | def _rename 178 | to = @current + @params[:name] 179 | 180 | perms_for_target = perms_for(@target) 181 | if perms_for_target[:rm] == false 182 | @response[:error] = 'Access Denied' 183 | return 184 | end 185 | 186 | perms_for_current = perms_for(@current) 187 | if perms_for_current[:write] == false 188 | @response[:error] = 'Access Denied' 189 | return 190 | end 191 | 192 | if to.exist? 193 | @response[:error] = "Unable to rename #{@target.ftype}. '#{to.basename}' already exists" 194 | elsif @target.rename(to) 195 | @params[:tree] = to.directory? 196 | @response[:select] = [to_hash(to)] 197 | _open(@current) 198 | else 199 | @response[:error] = "Unable to rename #{@target.ftype}" 200 | end 201 | end # of rename 202 | 203 | # 204 | def _upload 205 | if perms_for(@current)[:write] == false 206 | @response[:error] = 'Access Denied' 207 | return 208 | end 209 | 210 | select = [] 211 | @params[:upload].to_a.each do |file| 212 | dst = @current + @options[:original_filename_method].call(file) 213 | FileUtils.mv(file.path, dst.fullpath) 214 | FileUtils.chmod @options[:upload_file_mode], dst 215 | select << to_hash(dst) 216 | end 217 | @response[:select] = select 218 | _open(@current) 219 | end # of upload 220 | 221 | # 222 | def _ping 223 | @headers['Connection'] = 'Close' 224 | end # of ping 225 | 226 | # 227 | def _paste 228 | if perms_for(from_hash(@params[:dst]))[:write] == false 229 | @response[:error] = 'Access Denied' 230 | return 231 | end 232 | 233 | @targets.to_a.each do |src| 234 | if perms_for(src)[:read] == false || (@params[:cut].to_i > 0 && perms_for(src)[:rm] == false) 235 | @response[:error] ||= 'Some files were not copied.' 236 | @response[:errorData][src.basename.to_s] = "Access Denied" 237 | return 238 | else 239 | dst = from_hash(@params[:dst]) + src.basename 240 | if dst.exist? 241 | @response[:error] ||= 'Some files were unable to be copied' 242 | @response[:errorData][src.basename.to_s] = "already exists in '#{dst.dirname}'" 243 | else 244 | if @params[:cut].to_i > 0 245 | src.rename(dst) 246 | else 247 | if src.directory? 248 | FileUtils.cp_r(src.fullpath, dst.fullpath) 249 | else 250 | FileUtils.cp(src.fullpath, dst.fullpath) 251 | end 252 | end 253 | end 254 | end 255 | end 256 | @params[:tree] = true 257 | _open(@current) 258 | end # of paste 259 | 260 | # 261 | def _rm 262 | if @targets.empty? 263 | @response[:error] = "No files were selected for removal" 264 | else 265 | @targets.to_a.each do |target| 266 | remove_target(target) 267 | end 268 | @params[:tree] = true 269 | _open(@current) 270 | end 271 | end # of rm 272 | 273 | # 274 | def _duplicate 275 | if perms_for(@target)[:read] == false 276 | @response[:error] = 'Access Denied' 277 | @response[:errorData][@target.basename.to_s] = 'Unable to read' 278 | return 279 | end 280 | if perms_for(@target.dirname)[:write] == false 281 | @response[:error] = 'Access Denied' 282 | @response[:errorData][@target.dirname.to_s] = 'Unable to write' 283 | return 284 | end 285 | 286 | duplicate = @target.duplicate 287 | if @target.directory? 288 | FileUtils.cp_r(@target, duplicate.fullpath) 289 | else 290 | FileUtils.copy(@target, duplicate.fullpath) 291 | end 292 | @response[:select] = [to_hash(duplicate)] 293 | _open(@current) 294 | end # of duplicate 295 | 296 | # 297 | def _read 298 | if perms_for(@target)[:read] == true 299 | @response[:content] = @target.read 300 | else 301 | @response[:error] = 'Access Denied' 302 | end 303 | end # of read 304 | 305 | # 306 | def _edit 307 | perms = perms_for(@target) 308 | if perms[:read] == true && perms[:write] == true 309 | @target.open('w') { |f| f.write @params[:content] } 310 | @response[:file] = cdc_for(@target) 311 | else 312 | @response[:error] = 'Access Denied' 313 | end 314 | end # of edit 315 | 316 | # 317 | def _extract 318 | @response[:error] = 'Invalid Parameters' and return unless @target.file? && @current.directory? 319 | @response[:error] = 'Access Denied' and return unless perms_for(@target)[:read] == true && perms_for(@current)[:write] == true 320 | @response[:error] = 'No extractor available for this file type' and return if (extractor = @options[:extractors][mime_handler.for(@target)]).nil? 321 | cmd = ['cd', @current.to_s.shellescape, '&&', extractor.map(&:shellescape), @target.basename.to_s.shellescape].flatten.join(' ') 322 | if system(cmd) 323 | @params[:tree] = true 324 | _open(@current) 325 | else 326 | @response[:error] = 'Unable to extract files from archive' 327 | end 328 | end # of extract 329 | 330 | # 331 | def _archive 332 | @response[:error] = 'Invalid Parameters' and return unless !@targets.nil? && @targets.all?{|e| e.exist?} && @current.directory? 333 | @response[:error] = 'Access Denied' and return unless !@targets.nil? && @targets.all?{|e| perms_for(e)[:read]} && perms_for(@current)[:write] == true 334 | @response[:error] = 'No archiver available for this file type' and return if (archiver = @options[:archivers][@params[:type]]).nil? 335 | extension = archiver.shift 336 | basename = @params[:name] || @targets.first.basename_sans_extension 337 | archive = (@root + "#{basename}#{extension}").unique 338 | cmd = ['cd', @current.to_s.shellescape, '&&', archiver.map(&:shellescape), archive.to_s.shellescape, @targets.map{|t| t.basename.to_s.shellescape}].flatten.join(' ') 339 | if system(cmd) 340 | @response[:select] = [to_hash(archive)] 341 | _open(@current) 342 | else 343 | @response[:error] = 'Unable to create archive' 344 | end 345 | end # of archive 346 | 347 | # 348 | def _tmb 349 | if image_handler.nil? 350 | command_not_implemented 351 | else 352 | @response[:current] = to_hash(@current) 353 | @response[:images] = {} 354 | idx = 0 355 | @current.children.select{|e| mime_handler.for(e) =~ /image/}.each do |img| 356 | if idx >= @options[:thumbs_at_once] 357 | @response[:tmb] = true 358 | break 359 | end 360 | thumbnail = thumbnail_for(img) 361 | unless thumbnail.file? 362 | image_handler.thumbnail(img, thumbnail, :width => @options[:thumbs_size].to_i, :height => @options[:thumbs_size].to_i) 363 | @response[:images][to_hash(img)] = @options[:url] + '/' + thumbnail.path.to_s 364 | idx += 1 365 | end 366 | end 367 | end 368 | 369 | end # of tmb 370 | 371 | # 372 | def _resize 373 | if image_handler.nil? 374 | command_not_implemented 375 | else 376 | if @target.file? 377 | perms = perms_for(@target) 378 | if perms[:read] == true && perms[:write] == true 379 | image_handler.resize(@target, :width => @params[:width].to_i, :height => @params[:height].to_i) 380 | @response[:select] = [to_hash(@target)] 381 | _open(@current) 382 | else 383 | @response[:error] = 'Access Denied' 384 | end 385 | else 386 | @response[:error] = "Unable to resize file. It does not exist" 387 | end 388 | end 389 | end # of resize 390 | 391 | ################################################################################ 392 | private 393 | 394 | # 395 | def thumbnail_for(pathname) 396 | @thumb_directory + "#{to_hash(pathname)}.png" 397 | end 398 | 399 | # 400 | def remove_target(target) 401 | if target.directory? 402 | target.children.each do |child| 403 | remove_target(child) 404 | end 405 | end 406 | if perms_for(target)[:rm] == false 407 | @response[:error] ||= 'Some files/directories were unable to be removed' 408 | @response[:errorData][target.basename.to_s] = "Access Denied" 409 | else 410 | begin 411 | target.unlink 412 | if @options[:thumbs] && (thumbnail = thumbnail_for(target)).file? 413 | thumbnail.unlink 414 | end 415 | rescue 416 | @response[:error] ||= 'Some files/directories were unable to be removed' 417 | @response[:errorData][target.basename.to_s] = "Remove failed" 418 | end 419 | end 420 | end 421 | 422 | # 423 | def mime_handler 424 | @options[:mime_handler] 425 | end 426 | 427 | # 428 | def image_handler 429 | @options[:image_handler] 430 | end 431 | 432 | # 433 | def cwd_for(pathname) 434 | { 435 | :name => pathname.basename.to_s, 436 | :hash => to_hash(pathname), 437 | :mime => 'directory', 438 | :rel => pathname.is_root? ? @options[:home] : (@options[:home] + '/' + pathname.path.to_s), 439 | :size => 0, 440 | :date => pathname.mtime.to_s, 441 | }.merge(perms_for(pathname)) 442 | end 443 | 444 | def cdc_for(pathname) 445 | return nil if @options[:thumbs] && pathname.to_s == @thumb_directory.to_s 446 | response = { 447 | :name => pathname.basename.to_s, 448 | :hash => to_hash(pathname), 449 | :date => pathname.mtime.to_s, 450 | } 451 | response.merge! perms_for(pathname) 452 | 453 | if pathname.directory? 454 | response.merge!( 455 | :size => 0, 456 | :mime => 'directory' 457 | ) 458 | elsif pathname.file? 459 | response.merge!( 460 | :size => pathname.size, 461 | :mime => mime_handler.for(pathname), 462 | :url => (@options[:url] + '/' + pathname.path.to_s) 463 | ) 464 | 465 | if pathname.readable? && response[:mime] =~ /image/ && !image_handler.nil? 466 | response.merge!( 467 | :resize => true, 468 | :dim => image_handler.size(pathname) 469 | ) 470 | if @options[:thumbs] 471 | if (thumbnail = thumbnail_for(pathname)).exist? 472 | response.merge!( :tmb => (@options[:url] + '/' + thumbnail.path.to_s)) 473 | else 474 | @response[:tmb] = true 475 | end 476 | end 477 | end 478 | 479 | end 480 | 481 | if pathname.symlink? 482 | response.merge!( 483 | :link => to_hash(@root + pathname.readlink), # hash of file to which point link 484 | :linkTo => (@root + pathname.readlink).relative_to(pathname.dirname.path).to_s, # relative path to 485 | :parent => to_hash((@root + pathname.readlink).dirname) # hash of directory in which is linked file 486 | ) 487 | end 488 | 489 | return response 490 | end 491 | 492 | # 493 | def tree_for(root) 494 | root.children. 495 | select{ |child| child.directory? }. 496 | reject{ |child| @options[:thumbs] && child.to_s == @thumb_directory.to_s }. 497 | sort_by{|e| e.basename.to_s.downcase}. 498 | map { |child| 499 | {:name => child.basename.to_s, 500 | :hash => to_hash(child), 501 | :dirs => tree_for(child), 502 | }.merge(perms_for(child)) 503 | } 504 | end # of tree_for 505 | 506 | # 507 | def perms_for(pathname, options = {}) 508 | skip = [options[:skip]].flatten 509 | response = {} 510 | 511 | response[:read] = pathname.readable? if pathname.exist? 512 | response[:read] &&= specific_perm_for(pathname, :read) 513 | response[:read] &&= @options[:default_perms][:read] 514 | 515 | response[:write] = pathname.writable? if pathname.exist? 516 | response[:write] &&= specific_perm_for(pathname, :write) 517 | response[:write] &&= @options[:default_perms][:write] 518 | 519 | response[:rm] = !pathname.is_root? 520 | response[:rm] &&= specific_perm_for(pathname, :rm) 521 | response[:rm] &&= @options[:default_perms][:rm] 522 | 523 | response 524 | end # of perms_for 525 | 526 | # 527 | def specific_perm_for(pathname, perm) 528 | pathname = pathname.path if pathname.is_a?(ElFinder::Pathname) 529 | @options[:perms].select{ |k,v| pathname.to_s.send((k.is_a?(String) ? :== : :match), k) }.none?{|e| e.last[perm] == false} 530 | end # of specific_perm_for 531 | 532 | # 533 | def invalid_request 534 | @response[:error] = "Invalid command '#{@params[:cmd]}'" 535 | end # of invalid_request 536 | 537 | # 538 | def command_not_implemented 539 | @response[:error] = "Command '#{@params[:cmd]}' not yet implemented" 540 | end # of command_not_implemented 541 | 542 | end # of class Connector 543 | end # of module ElFinder 544 | --------------------------------------------------------------------------------