ftpd 0.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ftpd might be problematic. Click here for more details.

Files changed (62) hide show
  1. data/Gemfile +9 -0
  2. data/Gemfile.lock +43 -0
  3. data/LICENSE.md +9 -0
  4. data/README.md +57 -0
  5. data/Rakefile +8 -0
  6. data/VERSION +1 -0
  7. data/features/command_errors.feature +33 -0
  8. data/features/delete.feature +34 -0
  9. data/features/directory_navigation.feature +34 -0
  10. data/features/file_structure.feature +40 -0
  11. data/features/get.feature +62 -0
  12. data/features/list.feature +77 -0
  13. data/features/login.feature +54 -0
  14. data/features/mode.feature +40 -0
  15. data/features/name_list.feature +77 -0
  16. data/features/noop.feature +14 -0
  17. data/features/port.feature +25 -0
  18. data/features/put.feature +65 -0
  19. data/features/quit.feature +20 -0
  20. data/features/step_definitions/client_and_server_files.rb +24 -0
  21. data/features/step_definitions/client_files.rb +9 -0
  22. data/features/step_definitions/command.rb +5 -0
  23. data/features/step_definitions/connect.rb +15 -0
  24. data/features/step_definitions/delete.rb +15 -0
  25. data/features/step_definitions/directories.rb +22 -0
  26. data/features/step_definitions/error.rb +87 -0
  27. data/features/step_definitions/file_structure.rb +16 -0
  28. data/features/step_definitions/get.rb +16 -0
  29. data/features/step_definitions/invalid_commands.rb +11 -0
  30. data/features/step_definitions/line_endings.rb +7 -0
  31. data/features/step_definitions/list.rb +46 -0
  32. data/features/step_definitions/login.rb +69 -0
  33. data/features/step_definitions/mode.rb +15 -0
  34. data/features/step_definitions/noop.rb +13 -0
  35. data/features/step_definitions/passive.rb +3 -0
  36. data/features/step_definitions/port.rb +5 -0
  37. data/features/step_definitions/put.rb +16 -0
  38. data/features/step_definitions/quit.rb +15 -0
  39. data/features/step_definitions/server.rb +7 -0
  40. data/features/step_definitions/server_files.rb +18 -0
  41. data/features/step_definitions/type.rb +15 -0
  42. data/features/support/env.rb +4 -0
  43. data/features/support/file_templates/ascii_unix +4 -0
  44. data/features/support/file_templates/ascii_windows +4 -0
  45. data/features/support/file_templates/binary +0 -0
  46. data/features/support/test_client.rb +89 -0
  47. data/features/support/test_file_templates.rb +33 -0
  48. data/features/support/test_server.rb +52 -0
  49. data/features/syntax_errors.feature +15 -0
  50. data/features/type.feature +53 -0
  51. data/ftpd.gemspec +112 -0
  52. data/insecure-test-cert.pem +29 -0
  53. data/lib/ftpd.rb +6 -0
  54. data/lib/ftpd/FakeFtpServer.rb +736 -0
  55. data/lib/ftpd/FakeServer.rb +57 -0
  56. data/lib/ftpd/FakeTlsServer.rb +52 -0
  57. data/lib/ftpd/ObjectUtil.rb +66 -0
  58. data/lib/ftpd/TempDir.rb +54 -0
  59. data/lib/ftpd/q.rb +92 -0
  60. data/rake_tasks/cucumber.rake +7 -0
  61. data/rake_tasks/jeweler.rake +25 -0
  62. metadata +164 -0
@@ -0,0 +1,16 @@
1
+ When /^the client successfully gets (text|binary) "(.*?)"$/ \
2
+ do |mode, remote_path|
3
+ @client.get mode, remote_path
4
+ end
5
+
6
+ When /^the client gets (\S+) "(.*?)"$/ do |mode, path|
7
+ capture_error do
8
+ step %Q(the client successfully gets #{mode} "#{path}")
9
+ end
10
+ end
11
+
12
+ When /^the client gets with no path$/ do
13
+ capture_error do
14
+ @client.raw 'RETR'
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+ When /^the client sends an empty command$/ do
2
+ capture_error do
3
+ @client.raw ''
4
+ end
5
+ end
6
+
7
+ When /^the client sends a non-word command$/ do
8
+ capture_error do
9
+ @client.raw '*'
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ def line_ending_type(s)
2
+ if s =~ /\r\n/
3
+ :windows
4
+ else
5
+ :unix
6
+ end
7
+ end
@@ -0,0 +1,46 @@
1
+ class FileList
2
+
3
+ def initialize(lines)
4
+ @lines = lines
5
+ end
6
+
7
+ def filenames
8
+ @lines.map(&:split).map(&:last)
9
+ end
10
+
11
+ def long_form?
12
+ @lines.all? do |line|
13
+ line =~ /^[rwxSst-]{10}/
14
+ end
15
+ end
16
+
17
+ def short_form?
18
+ !long_form?
19
+ end
20
+
21
+ end
22
+
23
+ When /^the client lists the directory(?: "(.*?)")?$/ do |directory|
24
+ capture_error do
25
+ @list = FileList.new(@client.ls(*[directory].compact))
26
+ end
27
+ end
28
+
29
+ When /^the client name lists the directory(?: "(.*?)")?$/ do |directory|
30
+ capture_error do
31
+ @list = FileList.new(@client.nlst(*[directory].compact))
32
+ end
33
+ end
34
+
35
+ Then /^the file list should( not)? contain "(.*?)"$/ do |neg, filename|
36
+ matcher = if neg
37
+ :should_not
38
+ else
39
+ :should
40
+ end
41
+ @list.filenames.send(matcher, include(filename))
42
+ end
43
+
44
+ Then /^the file list should be in (long|short) form$/ do |form|
45
+ @list.should send("be_#{form}_form")
46
+ end
@@ -0,0 +1,69 @@
1
+ def logged_in?
2
+ step "the client lists the directory"
3
+ @error.nil?
4
+ end
5
+
6
+ def login(user, password)
7
+ capture_error do
8
+ @client.login user, password
9
+ end
10
+ end
11
+
12
+ Given /^a successful connection( with TLS)?$/ do |with_tls|
13
+ step 'the server is started'
14
+ step "the client connects#{with_tls}"
15
+ end
16
+
17
+ Given /^a successful login( with TLS)?$/ do |with_tls|
18
+ step "a successful connection#{with_tls}"
19
+ step 'the client logs in'
20
+ end
21
+
22
+ Given /^a failed login$/ do
23
+ step 'the server is started'
24
+ step 'the client connects'
25
+ step 'the client logs in with a bad password'
26
+ end
27
+
28
+ When /^the client logs in$/ do
29
+ login @server.user, @server.password
30
+ end
31
+
32
+ When /^the client logs in with a bad password$/ do
33
+ login @server.user, 'the-wrong-password'
34
+ end
35
+
36
+ When /^the client logs in with a bad user$/ do
37
+ login 'the-wrong-user', @server.password
38
+ end
39
+
40
+ Then /^the client should( not)? be logged in$/ do |neg|
41
+ matcher_method = if neg
42
+ :be_false
43
+ else
44
+ :be_true
45
+ end
46
+ logged_in?.should send(matcher_method)
47
+ end
48
+
49
+ When /^the client sends a password( with no parameter)?$/ do |no_param|
50
+ capture_error do
51
+ args = if no_param
52
+ []
53
+ else
54
+ [@server.password]
55
+ end
56
+ @client.raw 'PASS', *args
57
+ end
58
+ end
59
+
60
+ When /^the client sends a user( with no parameter)?$/ do |no_param|
61
+ capture_error do
62
+ args = if no_param
63
+ []
64
+ else
65
+ [@server.user]
66
+ end
67
+ @client.raw 'USER', *args
68
+ end
69
+ end
@@ -0,0 +1,15 @@
1
+ When /^the client successfully sets mode "(.*?)"$/ do |mode|
2
+ @client.raw 'MODE', mode
3
+ end
4
+
5
+ When /^the client sets mode "(.*?)"$/ do |mode|
6
+ capture_error do
7
+ step %Q'the client successfully sets mode "#{mode}"'
8
+ end
9
+ end
10
+
11
+ When /^the client sets mode with no parameter$/ do
12
+ capture_error do
13
+ @client.raw 'MODE'
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ When /^the client successfully does nothing( with a parameter)?$/ do |with_param|
2
+ if with_param
3
+ @client.raw 'NOOP', 'foo'
4
+ else
5
+ @client.noop
6
+ end
7
+ end
8
+
9
+ When /^the client does nothing( with a parameter)?$/ do |with_param|
10
+ capture_error do
11
+ step "the client successfully does nothing#{with_param}"
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ Given /^the client is in (passive|active) mode$/ do |mode|
2
+ @client.passive = mode == 'passive'
3
+ end
@@ -0,0 +1,5 @@
1
+ When /^the client sends PORT "(.*?)"$/ do |param|
2
+ capture_error do
3
+ @client.raw 'PORT', param
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ When /^the client successfully puts (text|binary) "(.*?)"$/ do
2
+ |mode, local_path|
3
+ @client.put mode, local_path
4
+ end
5
+
6
+ When /^the client puts (\S+) "(.*?)"$/ do |mode, path|
7
+ capture_error do
8
+ step %Q(the client successfully puts #{mode} "#{path}")
9
+ end
10
+ end
11
+
12
+ When /^the client puts with no path$/ do
13
+ capture_error do
14
+ @client.raw 'STOR'
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ When /^the client successfully quits$/ do
2
+ @client.quit
3
+ end
4
+
5
+ When /^the client quits$/ do
6
+ capture_error do
7
+ step 'the client successfully quits'
8
+ end
9
+ end
10
+
11
+ When /^the client quits with a parameter$/ do
12
+ capture_error do
13
+ @client.raw 'QUIT', 'foo'
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ Given /^the server is started$/ do
2
+ @server = TestServer.new
3
+ end
4
+
5
+ After do
6
+ @server.close if @server
7
+ end
@@ -0,0 +1,18 @@
1
+ Given /^the server has file "(.*?)"$/ do |remote_path|
2
+ @server.add_file remote_path
3
+ end
4
+
5
+ Then /^the server should( not)? have file "(.*?)"$/ do |neg, path|
6
+ matcher = if neg
7
+ :be_false
8
+ else
9
+ :be_true
10
+ end
11
+ @server.has_file?(path).should send(matcher)
12
+ end
13
+
14
+ Then /^the remote file "(.*?)" should have (unix|windows) line endings$/ do
15
+ |remote_path, line_ending_type|
16
+ line_ending_type(@server.file_contents(remote_path)).should ==
17
+ line_ending_type.to_sym
18
+ end
@@ -0,0 +1,15 @@
1
+ When /^the client successfully sets type "(.*?)"$/ do |type|
2
+ @client.raw 'TYPE', type
3
+ end
4
+
5
+ When /^the client sets type "(.*?)"$/ do |type|
6
+ capture_error do
7
+ step %Q'the client successfully sets type "#{type}"'
8
+ end
9
+ end
10
+
11
+ When /^the client sets type with no parameter$/ do
12
+ capture_error do
13
+ @client.raw 'TYPE'
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+ $LOAD_PATH << File.expand_path('../../lib', File.dirname(__FILE__))
2
+
3
+ require 'ftpd'
4
+ require 'stringio'
@@ -0,0 +1,4 @@
1
+ Billy was a chemist
2
+ but Billy is no more
3
+ For what he thought was H2O
4
+ Was H2SO4
@@ -0,0 +1,4 @@
1
+ Billy was a chemist
2
+ but Billy is no more
3
+ For what he thought was H2O
4
+ Was H2SO4
@@ -0,0 +1,89 @@
1
+ require 'double_bag_ftps'
2
+ require 'net/ftp'
3
+
4
+ class TestClient
5
+
6
+ extend Forwardable
7
+ include FileUtils
8
+
9
+ def initialize(opts = {})
10
+ @temp_dir = Dir.mktmpdir
11
+ @ftp = make_ftp(opts)
12
+ @templates = TestFileTemplates.new
13
+ end
14
+
15
+ def_delegators :@ftp,
16
+ :chdir,
17
+ :connect,
18
+ :delete,
19
+ :getbinaryfile,
20
+ :gettextfile,
21
+ :login,
22
+ :ls,
23
+ :nlst,
24
+ :noop,
25
+ :passive=,
26
+ :pwd,
27
+ :quit
28
+
29
+ def raw(*command)
30
+ @ftp.sendcmd *command.compact.join(' ')
31
+ end
32
+
33
+ def get(mode, remote_path)
34
+ method = "get#{mode}file"
35
+ @ftp.send method, remote_path, local_path(remote_path)
36
+ end
37
+
38
+ def put(mode, remote_path)
39
+ method = "put#{mode}file"
40
+ @ftp.send method, local_path(remote_path), remote_path
41
+ end
42
+
43
+ def add_file(path)
44
+ full_path = temp_path(path)
45
+ mkdir_p File.dirname(full_path)
46
+ File.open(full_path, 'wb') do |file|
47
+ file.puts @templates[File.basename(full_path)]
48
+ end
49
+ end
50
+
51
+ def file_contents(path)
52
+ File.open(temp_path(path), 'rb', &:read)
53
+ end
54
+
55
+ private
56
+
57
+ RAW_METHOD_REGEX = /^send_(.*)$/
58
+
59
+ def local_path(remote_path)
60
+ temp_path(File.basename(remote_path))
61
+ end
62
+
63
+ def temp_path(path)
64
+ File.expand_path(path, @temp_dir)
65
+ end
66
+
67
+ def make_ftp(opts)
68
+ tls = opts[:tls]
69
+ if tls
70
+ make_tls_ftp
71
+ else
72
+ make_non_tls_ftp
73
+ end
74
+ end
75
+
76
+ def make_tls_ftp
77
+ ftp = DoubleBagFTPS.new
78
+ context_opts = {
79
+ :verify_mode => OpenSSL::SSL::VERIFY_NONE
80
+ }
81
+ ftp.ssl_context = DoubleBagFTPS.create_ssl_context(context_opts)
82
+ ftp
83
+ end
84
+
85
+ def make_non_tls_ftp
86
+ Net::FTP.new
87
+ end
88
+
89
+ end
@@ -0,0 +1,33 @@
1
+ class TestFileTemplates
2
+
3
+ def [](filename)
4
+ if have_template?(filename)
5
+ read_template filename
6
+ else
7
+ default_template filename
8
+ end
9
+ end
10
+
11
+ private
12
+
13
+ def have_template?(filename)
14
+ File.exists?(template_path(filename))
15
+ end
16
+
17
+ def read_template(filename)
18
+ File.open(template_path(filename), 'r', &:read)
19
+ end
20
+
21
+ def template_path(filename)
22
+ File.expand_path(filename, templates_path)
23
+ end
24
+
25
+ def templates_path
26
+ File.expand_path('file_templates', File.dirname(__FILE__))
27
+ end
28
+
29
+ def default_template(filename)
30
+ "Contents of #{filename}"
31
+ end
32
+
33
+ end
@@ -0,0 +1,52 @@
1
+ require 'fileutils'
2
+ require 'forwardable'
3
+
4
+ class TestServer
5
+
6
+ extend Forwardable
7
+ include FileUtils
8
+
9
+ def initialize
10
+ @temp_dir = Dir.mktmpdir
11
+ @server = FakeFtpServer.new(@temp_dir)
12
+ @templates = TestFileTemplates.new
13
+ end
14
+
15
+ def close
16
+ @server.close
17
+ rm_rf @temp_dir
18
+ end
19
+
20
+ def host
21
+ 'localhost'
22
+ end
23
+
24
+ def add_file(path)
25
+ full_path = temp_path(path)
26
+ mkdir_p File.dirname(full_path)
27
+ File.open(full_path, 'wb') do |file|
28
+ file.puts @templates[File.basename(full_path)]
29
+ end
30
+ end
31
+
32
+ def has_file?(path)
33
+ full_path = temp_path(path)
34
+ File.exists?(full_path)
35
+ end
36
+
37
+ def file_contents(path)
38
+ full_path = temp_path(path)
39
+ File.open(full_path, 'rb', &:read)
40
+ end
41
+
42
+ def_delegator :@server, :password
43
+ def_delegator :@server, :port
44
+ def_delegator :@server, :user
45
+
46
+ private
47
+
48
+ def temp_path(path)
49
+ File.expand_path(path, @temp_dir)
50
+ end
51
+
52
+ end