ftpd 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.yardopts +1 -0
- data/Changelog.md +25 -1
- data/README.md +91 -10
- data/VERSION +1 -1
- data/doc/rfc-compliance.md +20 -20
- data/examples/example.rb +69 -11
- data/features/example/read_only.feature +63 -0
- data/features/ftp_server/append.feature +94 -0
- data/features/ftp_server/command_errors.feature +0 -2
- data/features/ftp_server/concurrent_sessions.feature +1 -1
- data/features/ftp_server/debug.feature +4 -2
- data/features/ftp_server/delete.feature +1 -1
- data/features/ftp_server/get.feature +1 -1
- data/features/ftp_server/get_tls.feature +2 -1
- data/features/ftp_server/implicit_tls.feature +2 -1
- data/features/ftp_server/invertability.feature +15 -0
- data/features/ftp_server/list.feature +1 -1
- data/features/ftp_server/list_tls.feature +2 -1
- data/features/ftp_server/login_auth_level_account.feature +51 -0
- data/features/ftp_server/{login.feature → login_auth_level_password.feature} +4 -8
- data/features/ftp_server/login_auth_level_user.feature +31 -0
- data/features/ftp_server/mkdir.feature +1 -1
- data/features/ftp_server/name_list.feature +1 -1
- data/features/ftp_server/name_list_tls.feature +2 -1
- data/features/ftp_server/put.feature +1 -1
- data/features/ftp_server/put_tls.feature +2 -1
- data/features/ftp_server/put_unique.feature +1 -1
- data/features/ftp_server/rename.feature +1 -1
- data/features/ftp_server/rmdir.feature +1 -1
- data/features/ftp_server/step_definitions/debug.rb +1 -1
- data/features/ftp_server/step_definitions/test_server.rb +16 -15
- data/features/ftp_server/type.feature +11 -8
- data/features/step_definitions/append.rb +15 -0
- data/features/step_definitions/client_and_server_files.rb +2 -2
- data/features/step_definitions/client_files.rb +5 -0
- data/features/step_definitions/connect.rb +1 -1
- data/features/step_definitions/error_replies.rb +0 -4
- data/features/step_definitions/login.rb +30 -20
- data/features/step_definitions/server_files.rb +20 -7
- data/features/support/example_server.rb +10 -2
- data/features/support/test_client.rb +18 -0
- data/features/support/test_file_templates.rb +1 -1
- data/features/support/test_server.rb +25 -4
- data/ftpd.gemspec +11 -3
- data/lib/ftpd.rb +2 -0
- data/lib/ftpd/auth_levels.rb +9 -0
- data/lib/ftpd/disk_file_system.rb +48 -19
- data/lib/ftpd/ftp_server.rb +13 -10
- data/lib/ftpd/read_only_disk_file_system.rb +22 -0
- data/lib/ftpd/session.rb +62 -29
- data/spec/disk_file_system_spec.rb +30 -0
- metadata +12 -4
data/.yardopts
CHANGED
data/Changelog.md
CHANGED
@@ -1,8 +1,32 @@
|
|
1
|
-
### 0.
|
1
|
+
### 0.4.0
|
2
2
|
|
3
3
|
Enhancements
|
4
4
|
|
5
5
|
* Improved driver and file-system documentation.
|
6
|
+
* Added {Ftpd::ReadOnlyDiskFileSystem read only disk file system}
|
7
|
+
* Example can be run with a read-only file system
|
8
|
+
* Supports three different levels of authentication:
|
9
|
+
* User
|
10
|
+
* User + Password
|
11
|
+
* User + Password + Account
|
12
|
+
* Added --auth switch to the example to select the authentication
|
13
|
+
level.
|
14
|
+
* Support APPE
|
15
|
+
* Support TYPE "A T" (ASCII/Telnet)
|
16
|
+
* Support TYPE "LOCAL 8"
|
17
|
+
* Added switches to example to set authentication values
|
18
|
+
* --user
|
19
|
+
* --password
|
20
|
+
* --account
|
21
|
+
|
22
|
+
API changes
|
23
|
+
|
24
|
+
* {Example::Driver#authenticate authenticate} now takes three
|
25
|
+
parameters (user, password, account). For compatability, it can be
|
26
|
+
defined to take only two, provided you are not doing account
|
27
|
+
authentication.
|
28
|
+
* Added {Ftpd::FtpServer#auth_level} option
|
29
|
+
* Added {Ftpd::DiskFileSystem::Append}
|
6
30
|
|
7
31
|
### 0.3.1
|
8
32
|
|
data/README.md
CHANGED
@@ -8,7 +8,8 @@ embedded in a program.
|
|
8
8
|
## A note about this README
|
9
9
|
|
10
10
|
This readme, and the other files, contains Yardoc markup, especially
|
11
|
-
for links to the API docs
|
11
|
+
for links to the API docs; those links don't display properly on
|
12
|
+
github. You'll find a properly rendered version
|
12
13
|
{http://rubydoc.info/gems/ftpd on rubydoc.info}
|
13
14
|
|
14
15
|
## HELLO WORLD
|
@@ -91,6 +92,77 @@ Here are the methods a file system may expose:
|
|
91
92
|
* {Ftpd::DiskFileSystem::List#dir dir}
|
92
93
|
* {Ftpd::DiskFileSystem::Rename#rename rename}
|
93
94
|
|
95
|
+
### DiskFileSystem
|
96
|
+
|
97
|
+
Ftpd includes a disk based file system:
|
98
|
+
|
99
|
+
class Driver
|
100
|
+
|
101
|
+
...
|
102
|
+
|
103
|
+
def file_system(user)
|
104
|
+
Ftpd::DiskFileSystem.new('/var/lib/ftp')
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
*Warning*: The DiskFileSystem allows file and directory modification
|
110
|
+
including writing, renaming, deleting, etc. If you want a read-only
|
111
|
+
file system, then use {Ftpd::ReadOnlyDiskFileSystem} instead.
|
112
|
+
|
113
|
+
The DiskFileSystem is composed out of modules:
|
114
|
+
|
115
|
+
* {Ftpd::DiskFileSystem::Base Base} - You will need this
|
116
|
+
* {Ftpd::DiskFileSystem::Delete Delete} - File deletion
|
117
|
+
* {Ftpd::DiskFileSystem::List List} - Directory listing
|
118
|
+
* {Ftpd::DiskFileSystem::Mkdir Mkdir} - Directory creation
|
119
|
+
* {Ftpd::DiskFileSystem::Read Read} - File reading
|
120
|
+
* {Ftpd::DiskFileSystem::Rename Rename} - File renaming
|
121
|
+
* {Ftpd::DiskFileSystem::Rmdir Rmdir} - Directory removal
|
122
|
+
* {Ftpd::DiskFileSystem::Write Write} - File writing
|
123
|
+
|
124
|
+
For example, to create a custom file system that allows reading and
|
125
|
+
writing only, then:
|
126
|
+
|
127
|
+
class CustomDiskFileSystem
|
128
|
+
include DiskFileSystem::Base
|
129
|
+
include DiskFileSystem::List
|
130
|
+
include DiskFileSystem::Read
|
131
|
+
include DiskFileSystem::Write
|
132
|
+
end
|
133
|
+
|
134
|
+
class Driver
|
135
|
+
|
136
|
+
...
|
137
|
+
|
138
|
+
def file_system(user)
|
139
|
+
CustomDiskFileSystem('/var/lib/ftp')
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
## LIST output format
|
145
|
+
|
146
|
+
By default, the LIST command uses Unix "ls -l" formatting:
|
147
|
+
|
148
|
+
-rw-r--r-- 1 user group 1234 Mar 3 08:38 foo
|
149
|
+
|
150
|
+
To switch to
|
151
|
+
{http://cr.yp.to/ftp/list/eplf.html Easily Parsed LIST format (EPLF)}
|
152
|
+
format:
|
153
|
+
|
154
|
+
ftp_server.list_formatter = Ftpd::ListFormat::Eplf
|
155
|
+
|
156
|
+
To create your own custom formatter, create a class with these
|
157
|
+
methods:
|
158
|
+
|
159
|
+
* {Ftpd::ListFormat::Ls#initialize initialize}
|
160
|
+
* {Ftpd::ListFormat::Ls#to_s to_s}
|
161
|
+
|
162
|
+
And register your class with the ftp_server before starting it:
|
163
|
+
|
164
|
+
ftp_server.list_formatter = MyListFormatter
|
165
|
+
|
94
166
|
## DEBUGGING
|
95
167
|
|
96
168
|
Ftpd can write debugging information (essentially a transcript of its
|
@@ -111,16 +183,25 @@ output without having to change any code.
|
|
111
183
|
|
112
184
|
## LIMITATIONS
|
113
185
|
|
114
|
-
Ftpd is not
|
115
|
-
to get by. {file:doc/rfc.md Here} is a list of RFCs, indicating
|
116
|
-
much of each Ftpd complies with.
|
186
|
+
Ftpd is not fully RFC compliant. It does most of RFC969, and enough
|
187
|
+
TLS to get by. {file:doc/rfc.md Here} is a list of RFCs, indicating
|
188
|
+
how much of each Ftpd complies with.
|
189
|
+
|
190
|
+
RFC does not meet the following
|
191
|
+
[RFC-1123](http://tools.ietf.org/rfc/rfc1123.txt) "MUST" requrements.
|
192
|
+
If FTPD met these requirements, but did not meet the "SHOULD"
|
193
|
+
requirements, it would be "conditionally compliant":
|
194
|
+
|
195
|
+
* Server-FTP handle Telnet options
|
196
|
+
* Support command STAT
|
197
|
+
|
198
|
+
RFC does not meet the following
|
199
|
+
[RFC-1123](http://tools.ietf.org/rfc/rfc1123.txt)
|
200
|
+
"SHOULD" requrements. If FTPD met both the "MUST" and the "SHOULD"
|
201
|
+
requirements, it would be "unconditionally compliant":
|
117
202
|
|
118
|
-
|
119
|
-
|
120
|
-
That's because the interface IP is used both for binding server ports,
|
121
|
-
_and_ for advertising to the client which IP to connect to. Binding
|
122
|
-
to 0.0.0.0 will work fine, but when the client tries to connect to
|
123
|
-
0.0.0.0, it won't get to the server.
|
203
|
+
* Idle timeout in server-FTP
|
204
|
+
* Configurable idle timeout
|
124
205
|
|
125
206
|
## RUBY COMPATABILITY
|
126
207
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/doc/rfc-compliance.md
CHANGED
@@ -22,10 +22,10 @@ pyftpdlib is what every FTP library wants to be when it grows up.
|
|
22
22
|
Commands supported:
|
23
23
|
|
24
24
|
ABOR No --- Abort transfer
|
25
|
-
ACCT
|
25
|
+
ACCT Yes 0.4.0 Specify user's account
|
26
26
|
ALLO Yes 0.2.0 Allocate storage space
|
27
27
|
Treated as a NOOP
|
28
|
-
APPE
|
28
|
+
APPE Yes 0.4.0 Append to file
|
29
29
|
CDUP Yes 0.1.0 Change to parent directory
|
30
30
|
CWD Yes 0.1.0 Change working directory
|
31
31
|
DELE Yes 0.1.0 Delete file
|
@@ -87,18 +87,18 @@ with "C" where FTPD complies, or "E" where compliance is not required.
|
|
87
87
|
| |T|D|Y|O|O|t
|
88
88
|
FEATURE |SECTION | | | |T|T|e
|
89
89
|
-------------------------------------------|---------------|-|-|-|-|-|--
|
90
|
-
Implement TYPE T if same as TYPE N |4.1.2.2 | |x| | | |
|
91
|
-
File/Record transform invertible if poss. |4.1.2.4 | |x| | | |
|
90
|
+
Implement TYPE T if same as TYPE N |4.1.2.2 | |x| | | | C
|
91
|
+
File/Record transform invertible if poss. |4.1.2.4 | |x| | | | C
|
92
92
|
Server-FTP implement PASV |4.1.2.6 |x| | | | | C
|
93
93
|
PASV is per-transfer |4.1.2.6 |x| | | | | C
|
94
94
|
NLST reply usable in RETR cmds |4.1.2.7 |x| | | | | C
|
95
95
|
Implied type for LIST and NLST |4.1.2.7 | |x| | | | C
|
96
|
-
SITE cmd for non-standard features |4.1.2.8 | |x| | | |
|
96
|
+
SITE cmd for non-standard features |4.1.2.8 | |x| | | | C
|
97
97
|
STOU cmd return pathname as specified |4.1.2.9 |x| | | | | C
|
98
98
|
Use TCP READ boundaries on control conn. |4.1.2.10 | | | | |x| C
|
99
99
|
Server-FTP send only correct reply format |4.1.2.11 |x| | | | | C
|
100
100
|
Server-FTP use defined reply code if poss. |4.1.2.11 | |x| | | | C
|
101
|
-
New reply code following Section 4.2 |4.1.2.11 | | |x| | |
|
101
|
+
New reply code following Section 4.2 |4.1.2.11 | | |x| | | E
|
102
102
|
Default data port same IP addr as ctl conn |4.1.2.12 |x| | | | | C
|
103
103
|
Server-FTP handle Telnet options |4.1.2.12 |x| | | | |
|
104
104
|
Handle "Experimental" directory cmds |4.1.3.1 | |x| | | | C
|
@@ -109,30 +109,30 @@ Sender assume 110 replies are synchronous |4.1.3.4 | | | | |x|
|
|
109
109
|
| | | | | | |
|
110
110
|
Support TYPE: | | | | | | |
|
111
111
|
ASCII - Non-Print (AN) |4.1.2.13 |x| | | | | C
|
112
|
-
ASCII - Telnet (AT) -- if same as AN |4.1.2.2 | |x| | | |
|
113
|
-
ASCII - Carriage Control (AC) |959 3.1.1.5.2 | | |x| | |
|
114
|
-
EBCDIC - (any form) |959 3.1.1.2 | | |x| | |
|
112
|
+
ASCII - Telnet (AT) -- if same as AN |4.1.2.2 | |x| | | | C
|
113
|
+
ASCII - Carriage Control (AC) |959 3.1.1.5.2 | | |x| | | E
|
114
|
+
EBCDIC - (any form) |959 3.1.1.2 | | |x| | | E
|
115
115
|
IMAGE |4.1.2.1 |x| | | | | C
|
116
|
-
LOCAL 8 |4.1.2.1 |x| | | | |
|
117
|
-
LOCAL m |4.1.2.1 | | |x| | |2
|
116
|
+
LOCAL 8 |4.1.2.1 |x| | | | | C
|
117
|
+
LOCAL m |4.1.2.1 | | |x| | |2 E
|
118
118
|
| | | | | | |
|
119
119
|
Support MODE: | | | | | | |
|
120
120
|
Stream |4.1.2.13 |x| | | | | C
|
121
|
-
Block |959 3.4.2 | | |x| | |
|
121
|
+
Block |959 3.4.2 | | |x| | | E
|
122
122
|
| | | | | | |
|
123
123
|
Support STRUCTURE: | | | | | | |
|
124
124
|
File |4.1.2.13 |x| | | | | C
|
125
125
|
Record |4.1.2.13 |x| | | | |3 E
|
126
|
-
Page |4.1.2.3 | | | |x| |
|
126
|
+
Page |4.1.2.3 | | | |x| | E
|
127
127
|
| | | | | | |
|
128
128
|
Support commands: | | | | | | |
|
129
129
|
USER |4.1.2.13 |x| | | | | C
|
130
130
|
PASS |4.1.2.13 |x| | | | | C
|
131
|
-
ACCT |4.1.2.13 |x| | | | |
|
131
|
+
ACCT |4.1.2.13 |x| | | | | C
|
132
132
|
CWD |4.1.2.13 |x| | | | | C
|
133
133
|
CDUP |4.1.2.13 |x| | | | | C
|
134
|
-
SMNT |959 5.3.1 | | |x| | |
|
135
|
-
REIN |959 5.3.1 | | |x| | |
|
134
|
+
SMNT |959 5.3.1 | | |x| | | E
|
135
|
+
REIN |959 5.3.1 | | |x| | | E
|
136
136
|
QUIT |4.1.2.13 |x| | | | | C
|
137
137
|
| | | | | | |
|
138
138
|
PORT |4.1.2.13 |x| | | | | C
|
@@ -144,19 +144,19 @@ Support commands: | | | | | | |
|
|
144
144
|
RETR |4.1.2.13 |x| | | | | C
|
145
145
|
STOR |4.1.2.13 |x| | | | | C
|
146
146
|
STOU |959 5.3.1 | | |x| | | C
|
147
|
-
APPE |4.1.2.13 |x| | | | |
|
147
|
+
APPE |4.1.2.13 |x| | | | | C
|
148
148
|
ALLO |959 5.3.1 | | |x| | | C
|
149
|
-
REST |959 5.3.1 | | |x| | |
|
149
|
+
REST |959 5.3.1 | | |x| | | E
|
150
150
|
RNFR |4.1.2.13 |x| | | | | C
|
151
151
|
RNTO |4.1.2.13 |x| | | | | C
|
152
|
-
ABOR |959 5.3.1 | | |x| | |
|
152
|
+
ABOR |959 5.3.1 | | |x| | | E
|
153
153
|
DELE |4.1.2.13 |x| | | | | C
|
154
154
|
RMD |4.1.2.13 |x| | | | | C
|
155
155
|
MKD |4.1.2.13 |x| | | | | C
|
156
156
|
PWD |4.1.2.13 |x| | | | | C
|
157
157
|
LIST |4.1.2.13 |x| | | | | C
|
158
158
|
NLST |4.1.2.13 |x| | | | | C
|
159
|
-
SITE |4.1.2.8 | | |x| | |
|
159
|
+
SITE |4.1.2.8 | | |x| | | E
|
160
160
|
STAT |4.1.2.13 |x| | | | |
|
161
161
|
SYST |4.1.2.13 |x| | | | | C
|
162
162
|
HELP |4.1.2.13 |x| | | | | C
|
data/examples/example.rb
CHANGED
@@ -13,15 +13,24 @@ module Example
|
|
13
13
|
|
14
14
|
class Arguments
|
15
15
|
|
16
|
+
attr_reader :account
|
17
|
+
attr_reader :auth_level
|
16
18
|
attr_reader :eplf
|
17
19
|
attr_reader :interface
|
20
|
+
attr_reader :password
|
18
21
|
attr_reader :port
|
22
|
+
attr_reader :read_only
|
19
23
|
attr_reader :tls
|
24
|
+
attr_reader :user
|
20
25
|
|
21
26
|
def initialize(argv)
|
22
27
|
@interface = 'localhost'
|
23
28
|
@tls = :explicit
|
24
29
|
@port = 0
|
30
|
+
@auth_level = 'password'
|
31
|
+
@user = ENV['LOGNAME']
|
32
|
+
@password = ''
|
33
|
+
@account = ''
|
25
34
|
op = option_parser
|
26
35
|
op.parse!(argv)
|
27
36
|
rescue OptionParser::ParseError => e
|
@@ -40,11 +49,32 @@ module Example
|
|
40
49
|
@interface = t
|
41
50
|
end
|
42
51
|
op.on('--tls [TYPE]', [:off, :explicit, :implicit],
|
43
|
-
'Select TLS support (off, explicit, implicit)'
|
52
|
+
'Select TLS support (off, explicit, implicit)',
|
53
|
+
'default = off') do |t|
|
44
54
|
@tls = t
|
45
55
|
end
|
46
56
|
op.on('--eplf', 'LIST uses EPLF format') do |t|
|
47
57
|
@eplf = t
|
58
|
+
end
|
59
|
+
op.on('--read-only', 'Prohibit put, delete, rmdir, etc.') do |t|
|
60
|
+
@read_only = t
|
61
|
+
end
|
62
|
+
op.on('--auth [LEVEL]', [:user, :password, :account],
|
63
|
+
'Set authorization level (user, password, account)',
|
64
|
+
'default = password') do |t|
|
65
|
+
@auth_level = t
|
66
|
+
end
|
67
|
+
op.on('-U', '--user NAME', 'User for authentication',
|
68
|
+
'defaults to current user') do |t|
|
69
|
+
@user = t
|
70
|
+
end
|
71
|
+
op.on('-P', '--password PW', 'Password for authentication',
|
72
|
+
'defaults to empty string') do |t|
|
73
|
+
@password = t
|
74
|
+
end
|
75
|
+
op.on('-A', '--account PW', 'Account for authentication',
|
76
|
+
'defaults to empty string') do |t|
|
77
|
+
@account = t
|
48
78
|
end
|
49
79
|
end
|
50
80
|
end
|
@@ -64,19 +94,32 @@ module Example
|
|
64
94
|
# Your driver's initialize method can be anything you need. Ftpd
|
65
95
|
# does not create an instance of your driver.
|
66
96
|
|
67
|
-
def initialize(user, password, data_dir)
|
97
|
+
def initialize(user, password, account, data_dir, read_only)
|
68
98
|
@user = user
|
69
99
|
@password = password
|
100
|
+
@account = account
|
70
101
|
@data_dir = data_dir
|
102
|
+
@read_only = read_only
|
71
103
|
end
|
72
104
|
|
73
105
|
# Return true if the user should be allowed to log in.
|
74
106
|
# @param user [String]
|
75
107
|
# @param password [String]
|
108
|
+
# @param account [String]
|
76
109
|
# @return [Boolean]
|
77
|
-
|
78
|
-
|
79
|
-
|
110
|
+
#
|
111
|
+
# Depending upon the server's auth_level, some of these parameters
|
112
|
+
# may be nil. A parameter with a nil value is not required for
|
113
|
+
# authentication. Here are the parameters that are non-nil for
|
114
|
+
# each auth_level:
|
115
|
+
# * :user (user)
|
116
|
+
# * :password (user, password)
|
117
|
+
# * :account (user, password, account)
|
118
|
+
|
119
|
+
def authenticate(user, password, account)
|
120
|
+
user == @user &&
|
121
|
+
(password.nil? || password == @password) &&
|
122
|
+
(account.nil? || account == @account)
|
80
123
|
end
|
81
124
|
|
82
125
|
# Return the file system to use for a user.
|
@@ -84,7 +127,11 @@ module Example
|
|
84
127
|
# @return A file system driver that quacks like {Ftpd::DiskFileSystem}
|
85
128
|
|
86
129
|
def file_system(user)
|
87
|
-
|
130
|
+
if @read_only
|
131
|
+
Ftpd::ReadOnlyDiskFileSystem
|
132
|
+
else
|
133
|
+
Ftpd::DiskFileSystem
|
134
|
+
end.new(@data_dir)
|
88
135
|
end
|
89
136
|
|
90
137
|
end
|
@@ -99,7 +146,8 @@ module Example
|
|
99
146
|
@args = Arguments.new(argv)
|
100
147
|
@data_dir = Ftpd::TempDir.make
|
101
148
|
create_files
|
102
|
-
@driver = Driver.new(user, password,
|
149
|
+
@driver = Driver.new(user, password, account,
|
150
|
+
@data_dir, @args.read_only)
|
103
151
|
@server = Ftpd::FtpServer.new(@driver)
|
104
152
|
@server.interface = @args.interface
|
105
153
|
@server.port = @args.port
|
@@ -108,6 +156,7 @@ module Example
|
|
108
156
|
if @args.eplf
|
109
157
|
@server.list_formatter = Ftpd::ListFormat::Eplf
|
110
158
|
end
|
159
|
+
@server.auth_level = auth_level
|
111
160
|
@server.start
|
112
161
|
display_connection_info
|
113
162
|
create_connection_script
|
@@ -121,6 +170,10 @@ module Example
|
|
121
170
|
|
122
171
|
HOST = 'localhost'
|
123
172
|
|
173
|
+
def auth_level
|
174
|
+
Ftpd.const_get("AUTH_#{@args.auth_level.upcase}")
|
175
|
+
end
|
176
|
+
|
124
177
|
def create_files
|
125
178
|
create_file 'README',
|
126
179
|
"This file, and the directory it is in, will go away\n"
|
@@ -138,8 +191,9 @@ module Example
|
|
138
191
|
def display_connection_info
|
139
192
|
puts "Interface: #{@server.interface}"
|
140
193
|
puts "Port: #{@server.bound_port}"
|
141
|
-
puts "User: #{user}"
|
142
|
-
puts "Pass: #{password}"
|
194
|
+
puts "User: #{user.inspect}"
|
195
|
+
puts "Pass: #{password.inspect}" if auth_level >= Ftpd::AUTH_PASSWORD
|
196
|
+
puts "Acctount: #{account.inspect}" if auth_level >= Ftpd::AUTH_ACCOUNT
|
143
197
|
puts "TLS: #{@args.tls}"
|
144
198
|
puts "Directory: #{@data_dir}"
|
145
199
|
puts "URI: ftp://#{HOST}:#{@server.bound_port}"
|
@@ -166,11 +220,15 @@ module Example
|
|
166
220
|
end
|
167
221
|
|
168
222
|
def user
|
169
|
-
|
223
|
+
@args.user
|
170
224
|
end
|
171
225
|
|
172
226
|
def password
|
173
|
-
|
227
|
+
@args.password
|
228
|
+
end
|
229
|
+
|
230
|
+
def account
|
231
|
+
@args.account
|
174
232
|
end
|
175
233
|
|
176
234
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
Feature: Example
|
2
|
+
|
3
|
+
As a programmer
|
4
|
+
I want to start a read-only server
|
5
|
+
So that nobody can modify the file system I expose
|
6
|
+
|
7
|
+
Background:
|
8
|
+
Given the example has argument "--read-only"
|
9
|
+
And the example server is started
|
10
|
+
|
11
|
+
Scenario: Fetch README
|
12
|
+
Given a successful login
|
13
|
+
When the client successfully gets text "README"
|
14
|
+
Then the local file "README" should match the remote file
|
15
|
+
|
16
|
+
Scenario: Fetch README
|
17
|
+
Given a successful login
|
18
|
+
When the client successfully gets text "README"
|
19
|
+
Then the local file "README" should match the remote file
|
20
|
+
|
21
|
+
Scenario: List
|
22
|
+
Given a successful login
|
23
|
+
When the client successfully lists the directory
|
24
|
+
Then the file list should be in long form
|
25
|
+
And the file list should contain "README"
|
26
|
+
|
27
|
+
Scenario: Name List
|
28
|
+
Given a successful login
|
29
|
+
When the client successfully name-lists the directory
|
30
|
+
Then the file list should be in short form
|
31
|
+
And the file list should contain "README"
|
32
|
+
|
33
|
+
Scenario: Put
|
34
|
+
Given a successful login
|
35
|
+
And the client has file "foo"
|
36
|
+
When the client puts text "foo"
|
37
|
+
Then the server returns an unimplemented command error
|
38
|
+
|
39
|
+
Scenario: Put unique
|
40
|
+
Given a successful login
|
41
|
+
And the client has file "foo"
|
42
|
+
When the client stores unique "foo"
|
43
|
+
Then the server returns an unimplemented command error
|
44
|
+
|
45
|
+
Scenario: Delete
|
46
|
+
Given a successful login
|
47
|
+
When the client deletes "README"
|
48
|
+
Then the server returns an unimplemented command error
|
49
|
+
|
50
|
+
Scenario: Mkdir
|
51
|
+
Given a successful login
|
52
|
+
When the client makes directory "foo"
|
53
|
+
Then the server returns an unimplemented command error
|
54
|
+
|
55
|
+
Scenario: Rename
|
56
|
+
Given a successful login
|
57
|
+
When the client renames "README" to "foo"
|
58
|
+
Then the server returns an unimplemented command error
|
59
|
+
|
60
|
+
Scenario: Rmdir
|
61
|
+
Given a successful login
|
62
|
+
When the client removes directory "foo"
|
63
|
+
Then the server returns an unimplemented command error
|