em-ftpd-memory 0.0.1 → 0.0.2
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.
- checksums.yaml +4 -4
- data/em-ftpd-memory.gemspec +1 -1
- data/lib/em/ftpd/memory/authenticator.rb +13 -10
- data/lib/em/ftpd/memory/driver.rb +21 -11
- data/lib/em/ftpd/memory/filesystem.rb +154 -28
- data/test/test_authenticator.rb +115 -0
- data/test/test_ftpd-memory.rb +6 -37
- data/test/test_memory_filesystem.rb +182 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8fd32c31bff6d70f1558c6909462a3edb19d675a
|
4
|
+
data.tar.gz: 99a62b6e7e4cdac319b33b813d2d1f26660a8fe7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d2ac6295de54b6b0bc471203b4988b15f66fefa3bdd012a3369811beacd4a2190c5dd1babfd582a26bfed58fd9d5886380aa11de26ab06498f8c2a8bce148cd
|
7
|
+
data.tar.gz: 49c64f601a8dc2201e2237fe1847ad22f2168533261970d1f94c10d6139c0642c01a4cf53ee47b8866be9b3ac4b06e1bbd42a9d8ab5ff764e3f66516502253e5
|
data/em-ftpd-memory.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "em-ftpd-memory"
|
7
|
-
spec.version = "0.0.
|
7
|
+
spec.version = "0.0.2"
|
8
8
|
spec.authors = ["chrislee35"]
|
9
9
|
spec.email = ["rubygems@chrislee.dhs.org"]
|
10
10
|
spec.summary = %q{Memory-based backing store for em-ftpd}
|
@@ -3,10 +3,12 @@ require 'digest/md5'
|
|
3
3
|
|
4
4
|
module EM::FTPD::Memory
|
5
5
|
class User < Struct.new(:name, :credential); end
|
6
|
-
class
|
6
|
+
class InvalidPasswordAlgorithmError < StandardError; end
|
7
7
|
class NoSuchUserError < StandardError; end
|
8
|
-
class
|
8
|
+
class InvalidCredentialError < StandardError; end
|
9
9
|
class ExpiredCredentialError < StandardError; end
|
10
|
+
class MalformatedCredentialError < StandardError; end
|
11
|
+
class NoFurtherCredentialsAvailable < StandardError; end
|
10
12
|
|
11
13
|
class Authenticator
|
12
14
|
@@realms = Hash.new
|
@@ -21,6 +23,10 @@ module EM::FTPD::Memory
|
|
21
23
|
def initialize(options = {})
|
22
24
|
@users = Hash.new
|
23
25
|
@pwalgo = options["pwalgo"] || "plain"
|
26
|
+
@pwalgo = "#{@pwalgo}_authentication".to_sym
|
27
|
+
unless self.respond_to?(@pwalgo)
|
28
|
+
raise InvalidPasswordAlgorithmError.new
|
29
|
+
end
|
24
30
|
end
|
25
31
|
|
26
32
|
def <<(user)
|
@@ -35,18 +41,12 @@ module EM::FTPD::Memory
|
|
35
41
|
if @users[username].nil?
|
36
42
|
raise NoSuchUserError.new
|
37
43
|
end
|
38
|
-
|
39
|
-
algo = "#{@pwalgo}_authentication".to_sym
|
40
|
-
if self.respond_to?(algo)
|
41
|
-
self.send(algo, username, credential)
|
42
|
-
else
|
43
|
-
raise InvalidPasswordAlgorithmError.new
|
44
|
-
end
|
44
|
+
self.send(@pwalgo, username, credential)
|
45
45
|
end
|
46
46
|
|
47
47
|
def plain_authentication(username, credential)
|
48
48
|
if @users[username].credential != credential
|
49
|
-
raise
|
49
|
+
raise InvalidCredentialError.new
|
50
50
|
else
|
51
51
|
return true
|
52
52
|
end
|
@@ -54,6 +54,9 @@ module EM::FTPD::Memory
|
|
54
54
|
|
55
55
|
def timed_md5_authentication(username, credential)
|
56
56
|
seed, time, hash = credential.split(/:/, 3)
|
57
|
+
if hash.nil? or hash.length != 32
|
58
|
+
raise MalformatedCredentialError.new
|
59
|
+
end
|
57
60
|
if (time.to_i - Time.now.to_i).abs > 300
|
58
61
|
raise ExpiredCredentialError.new
|
59
62
|
else
|
@@ -3,21 +3,30 @@ module EM::FTPD::Memory
|
|
3
3
|
def initialize(options = {})
|
4
4
|
filesystem_name = options["filesystem_name"] || "default"
|
5
5
|
realm = options["authentication_realm"] || "default"
|
6
|
-
@fs = FileSystem.
|
6
|
+
@fs = FileSystem.getFileSystem(filesystem_name)
|
7
7
|
@authenticator = Authenticator.getAuthenticatorByRealm(realm, options)
|
8
|
+
@authenticated_user = nil
|
9
|
+
@server = Kernel.caller[0]
|
10
|
+
begin
|
11
|
+
$stderr.puts @server
|
12
|
+
rescue => e
|
13
|
+
$stderr.puts e
|
14
|
+
$stderr.puts e.backtrace
|
15
|
+
end
|
8
16
|
end
|
9
17
|
|
10
18
|
def change_dir(path, &block)
|
11
|
-
yield @fs.
|
19
|
+
yield @fs.change_dir(path, @authenticated_user)
|
12
20
|
end
|
13
21
|
|
14
22
|
def dir_contents(path, &block)
|
15
|
-
yield @fs.list_files(path)
|
23
|
+
yield @fs.list_files(path, @authenticated_user)
|
16
24
|
end
|
17
25
|
|
18
26
|
def authenticate(user, pass, &block)
|
19
27
|
begin
|
20
28
|
@authenticator.authenticate(user, pass)
|
29
|
+
@authenticated_user = user
|
21
30
|
yield true
|
22
31
|
rescue Exception => e
|
23
32
|
#puts e.backtrace
|
@@ -26,31 +35,32 @@ module EM::FTPD::Memory
|
|
26
35
|
end
|
27
36
|
|
28
37
|
def bytes(path, &block)
|
29
|
-
yield @fs.file_size(path)
|
38
|
+
yield @fs.file_size(path, @authenticated_user)
|
30
39
|
end
|
31
40
|
|
32
41
|
def get_file(path, &block)
|
33
|
-
yield @fs.file_contents(path)
|
42
|
+
yield @fs.file_contents(path, @authenticated_user)
|
34
43
|
end
|
35
44
|
|
36
45
|
def put_file(path, data, &block)
|
37
|
-
yield @fs.create_file(path, data)
|
46
|
+
yield @fs.create_file(path, data, @authenticated_user)
|
38
47
|
end
|
39
48
|
|
40
49
|
def delete_file(path, &block)
|
41
|
-
yield @fs.
|
50
|
+
yield @fs.delete_file(path, @authenticated_user)
|
42
51
|
end
|
43
52
|
|
44
53
|
def delete_dir(path, &block)
|
45
|
-
yield @fs.delete_dir(path)
|
54
|
+
yield @fs.delete_dir(path, @authenticated_user)
|
46
55
|
end
|
47
56
|
|
48
57
|
def rename(from, to, &block)
|
49
|
-
yield @fs.rename(from, to)
|
58
|
+
yield @fs.rename(from, to, @authenticated_user)
|
50
59
|
end
|
51
60
|
|
52
61
|
def make_dir(path, &block)
|
53
|
-
yield @fs.create_dir(path)
|
54
|
-
end
|
62
|
+
yield @fs.create_dir(path, @authenticated_user)
|
63
|
+
end
|
64
|
+
|
55
65
|
end
|
56
66
|
end
|
@@ -1,7 +1,9 @@
|
|
1
1
|
module EM::FTPD::Memory
|
2
|
+
class InvalidPermissionsError < StandardError; end
|
3
|
+
|
2
4
|
class FileSystem
|
3
5
|
@@filesystems = Hash.new
|
4
|
-
def self.
|
6
|
+
def self.getFileSystem(name)
|
5
7
|
if @@filesystems[name].nil?
|
6
8
|
@@filesystems[name] = FileSystem.new
|
7
9
|
end
|
@@ -9,7 +11,21 @@ module EM::FTPD::Memory
|
|
9
11
|
return @@filesystems[name]
|
10
12
|
end
|
11
13
|
|
14
|
+
def self.destroyFileSystem(name, force = false)
|
15
|
+
unless @@filesystems[name].nil?
|
16
|
+
if force
|
17
|
+
@@filesystems[name].destroy
|
18
|
+
@@filesystems.delete(name)
|
19
|
+
else
|
20
|
+
if @@filesystems[name].list_files("/").empty?
|
21
|
+
@@filesystems.delete(name)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
12
27
|
def initialize()
|
28
|
+
@root_entry = EM::FTPD::DirectoryItem.new(:name => 'root', :directory => true, :size => 0, :permissions => 'rwxrwxrwx', :owner => 'root', :group => 'root')
|
13
29
|
@root = {
|
14
30
|
'/' => Array.new
|
15
31
|
}
|
@@ -20,39 +36,30 @@ module EM::FTPD::Memory
|
|
20
36
|
is_dir(path) || is_file(path)
|
21
37
|
end
|
22
38
|
|
23
|
-
def
|
24
|
-
|
39
|
+
def chdir(path, user = nil)
|
40
|
+
is_dir(path) && use_allowed(path, :list, user)
|
25
41
|
end
|
26
42
|
|
27
|
-
def
|
43
|
+
def list_files(path, user = nil)
|
44
|
+
return [] unless use_allowed?(path, :list, user)
|
45
|
+
@root[path] || [] # should this return false?
|
46
|
+
end
|
47
|
+
|
48
|
+
def file_size(path, user = nil)
|
49
|
+
return false unless use_allowed?(path, :size, user)
|
28
50
|
f = get_file(path)
|
29
51
|
return false unless f
|
30
52
|
f.size
|
31
53
|
end
|
32
54
|
|
33
|
-
def file_contents(path)
|
55
|
+
def file_contents(path, user = nil)
|
56
|
+
return false unless use_allowed?(path, :read, user)
|
34
57
|
# nil || false => false
|
35
58
|
@contents[path] || false
|
36
59
|
end
|
37
60
|
|
38
|
-
def
|
39
|
-
|
40
|
-
basename = File.basename(path)
|
41
|
-
if is_dir(dirname)
|
42
|
-
return @root[dirname].find {|file| file.directory == false && file.name == basename}
|
43
|
-
end
|
44
|
-
nil
|
45
|
-
end
|
46
|
-
|
47
|
-
def is_file(path)
|
48
|
-
@contents[path] || false
|
49
|
-
end
|
50
|
-
|
51
|
-
def is_dir(path)
|
52
|
-
@root[path] != nil
|
53
|
-
end
|
54
|
-
|
55
|
-
def create_file(path, data)
|
61
|
+
def create_file(path, data, user = "nobody")
|
62
|
+
return false unless use_allowed?(path, :create, user)
|
56
63
|
dirname = File.dirname(path)
|
57
64
|
basename = File.basename(path)
|
58
65
|
if is_dir(dirname)
|
@@ -70,8 +77,9 @@ module EM::FTPD::Memory
|
|
70
77
|
end
|
71
78
|
end
|
72
79
|
|
73
|
-
def
|
80
|
+
def delete_file(path, user = nil)
|
74
81
|
if is_file(path)
|
82
|
+
return false unless use_allowed?(path, :delete, user)
|
75
83
|
dirname = File.dirname(path)
|
76
84
|
basename = File.basename(path)
|
77
85
|
@root[dirname].reject! {|file| file.directory == false && file.name == basename}
|
@@ -81,8 +89,9 @@ module EM::FTPD::Memory
|
|
81
89
|
false
|
82
90
|
end
|
83
91
|
|
84
|
-
def delete_dir(path)
|
92
|
+
def delete_dir(path, user = nil)
|
85
93
|
if is_dir(path) && @root[path].empty?
|
94
|
+
return false unless use_allowed?(path, :delete, user)
|
86
95
|
@root.delete(path)
|
87
96
|
dirname = File.dirname(path)
|
88
97
|
basename = File.basename(path)
|
@@ -92,8 +101,9 @@ module EM::FTPD::Memory
|
|
92
101
|
false
|
93
102
|
end
|
94
103
|
|
95
|
-
def create_dir(path)
|
104
|
+
def create_dir(path, user = "nobody")
|
96
105
|
if not exist?(path)
|
106
|
+
return false unless use_allowed?(path, :create, user)
|
97
107
|
dirname = File.dirname(path)
|
98
108
|
basename = File.basename(path)
|
99
109
|
if is_dir(dirname)
|
@@ -105,9 +115,11 @@ module EM::FTPD::Memory
|
|
105
115
|
return false
|
106
116
|
end
|
107
117
|
|
108
|
-
def rename(from, to)
|
118
|
+
def rename(from, to, user = nil)
|
109
119
|
return false if exist?(to)
|
110
120
|
return false unless exist?(from)
|
121
|
+
return false unless use_allowed?(from, :delete, user)
|
122
|
+
return false unless use_allowed?(to, :create, user)
|
111
123
|
|
112
124
|
from_dirname = File.dirname(from)
|
113
125
|
from_basename = File.basename(from)
|
@@ -117,7 +129,8 @@ module EM::FTPD::Memory
|
|
117
129
|
if from_dirname == to_dirname
|
118
130
|
@root[from_dirname].find {|file| file.name == from_basename}.name = to_basename
|
119
131
|
else
|
120
|
-
entry = @root[from_dirname].
|
132
|
+
entry = @root[from_dirname].find {|file| file.name == from_basename}
|
133
|
+
@root[from_dirname] -= [entry]
|
121
134
|
entry.name = to_basename
|
122
135
|
@root[to_dirname] << entry
|
123
136
|
end
|
@@ -133,6 +146,119 @@ module EM::FTPD::Memory
|
|
133
146
|
end
|
134
147
|
return true
|
135
148
|
end
|
149
|
+
|
150
|
+
def destroy
|
151
|
+
@root.each_key do |d|
|
152
|
+
@root.delete(d)
|
153
|
+
end
|
154
|
+
@contents.each_key do |f|
|
155
|
+
@contents.delete(f)
|
156
|
+
end
|
157
|
+
GC.start
|
158
|
+
end
|
159
|
+
|
160
|
+
def set_permissions(path, permissions, user = nil)
|
161
|
+
return false unless exist?(path)
|
162
|
+
raise InvalidPermissionsError.new if permissions.nil?
|
163
|
+
raise InvalidPermissionsError.new(permissions.to_s) unless permissions.class == String
|
164
|
+
raise InvalidPermissionsError.new(permissions) unless permissions =~ /^[r\.][w\.][x\.][r\.][w\.][x\.][r\.][w\.][x\.]$/
|
165
|
+
entry = get_entry(path)
|
166
|
+
return false unless entry
|
167
|
+
return false unless user and (entry.owner == user or user == "root")
|
168
|
+
entry.permissions = permissions
|
169
|
+
true
|
170
|
+
end
|
171
|
+
|
172
|
+
def set_owner(path, owner, user = nil)
|
173
|
+
return false unless exist?(path) and owner and owner.class == String
|
174
|
+
entry = get_entry(path)
|
175
|
+
return false unless user and user == "root"
|
176
|
+
return false unless entry
|
177
|
+
entry.owner = owner
|
178
|
+
true
|
179
|
+
end
|
180
|
+
|
181
|
+
#private
|
182
|
+
|
183
|
+
def get_entry(path)
|
184
|
+
return @root_entry if path == '/'
|
185
|
+
dirname = File.dirname(path)
|
186
|
+
basename = File.basename(path)
|
187
|
+
if is_dir(dirname)
|
188
|
+
return @root[dirname].find {|entry| entry.name == basename}
|
189
|
+
end
|
190
|
+
nil
|
191
|
+
end
|
192
|
+
|
193
|
+
def get_file(path)
|
194
|
+
dirname = File.dirname(path)
|
195
|
+
basename = File.basename(path)
|
196
|
+
if is_dir(dirname)
|
197
|
+
return @root[dirname].find {|file| file.directory == false && file.name == basename}
|
198
|
+
end
|
199
|
+
nil
|
200
|
+
end
|
201
|
+
|
202
|
+
def is_file(path)
|
203
|
+
@contents[path] || false
|
204
|
+
end
|
205
|
+
|
206
|
+
def is_dir(path)
|
207
|
+
@root[path] != nil
|
208
|
+
end
|
209
|
+
|
210
|
+
def use_allowed?(path, use, username)
|
211
|
+
return true if username == 'root'
|
212
|
+
|
213
|
+
dirname = File.dirname(path)
|
214
|
+
basename = File.basename(path)
|
215
|
+
# to do anything, you must be able to rx into the directory containing the entry
|
216
|
+
cwd = '/'
|
217
|
+
dirname.split(/\//).each do |dir|
|
218
|
+
next if dir == '/'
|
219
|
+
cwd << dir
|
220
|
+
return false unless allowed?(cwd, "rx", username)
|
221
|
+
cwd << '/'
|
222
|
+
end
|
223
|
+
|
224
|
+
case use
|
225
|
+
when :read
|
226
|
+
return allowed?(path, 'r', username)
|
227
|
+
when :write
|
228
|
+
return allowed?(path, 'w', username)
|
229
|
+
when :list
|
230
|
+
return allowed?(path, 'rx', username)
|
231
|
+
when :size
|
232
|
+
return true # since we've already checked everything
|
233
|
+
when :delete
|
234
|
+
return allowed?(dirname, "rwx", username)
|
235
|
+
when :create
|
236
|
+
return allowed?(dirname, "rwx", username)
|
237
|
+
else
|
238
|
+
return false
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def allowed?(path, required_permissions, username)
|
243
|
+
entry = get_entry(path)
|
244
|
+
permissions = entry.permissions || 'rwxrwxrwx'
|
245
|
+
return false unless entry
|
246
|
+
if username.nil?
|
247
|
+
perms = permissions[6,3]
|
248
|
+
elsif entry.owner == username
|
249
|
+
perms = permissions[0,3]
|
250
|
+
else
|
251
|
+
perms = permissions[6,3]
|
252
|
+
end
|
253
|
+
|
254
|
+
return true if perms == "rwx"
|
255
|
+
required_permissions.each_char do |c|
|
256
|
+
if perms.index(c).nil?
|
257
|
+
return false
|
258
|
+
end
|
259
|
+
end
|
260
|
+
return true
|
261
|
+
end
|
136
262
|
|
137
263
|
end
|
138
264
|
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
unless Kernel.respond_to?(:require_relative)
|
2
|
+
module Kernel
|
3
|
+
def require_relative(path)
|
4
|
+
require File.join(File.dirname(caller[0]), path.to_str)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
require_relative 'helper'
|
10
|
+
require 'digest/md5'
|
11
|
+
include EM::FTPD::Memory
|
12
|
+
|
13
|
+
class TestAuthenticator < Minitest::Test
|
14
|
+
def test_invalid_pwalgo
|
15
|
+
options = {
|
16
|
+
"pwalgo" => "nogood",
|
17
|
+
"authentication_realm" => "invalid"
|
18
|
+
}
|
19
|
+
assert_raises(InvalidPasswordAlgorithmError) do
|
20
|
+
Authenticator.getAuthenticatorByRealm(options["authentication_realm"], options)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_plain_login
|
25
|
+
options = {
|
26
|
+
"pwalgo" => "plain",
|
27
|
+
"authentication_realm" => "plain"
|
28
|
+
}
|
29
|
+
auth = Authenticator.getAuthenticatorByRealm(options["authentication_realm"], options)
|
30
|
+
auth << User.new("test", "test")
|
31
|
+
assert_raises(NoSuchUserError) do
|
32
|
+
auth.authenticate("jerk", "noway")
|
33
|
+
end
|
34
|
+
|
35
|
+
assert_raises(InvalidCredentialError) do
|
36
|
+
auth.authenticate("test", "noway")
|
37
|
+
end
|
38
|
+
|
39
|
+
assert(auth.authenticate("test", "test"))
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_time_based_login
|
43
|
+
options = {
|
44
|
+
"pwalgo" => "timed_md5",
|
45
|
+
"authentication_realm" => "time_based"
|
46
|
+
}
|
47
|
+
auth = Authenticator.getAuthenticatorByRealm(options["authentication_realm"], options)
|
48
|
+
auth << User.new("test", "test")
|
49
|
+
assert_raises(NoSuchUserError) do
|
50
|
+
auth.authenticate("jerk", "noway")
|
51
|
+
end
|
52
|
+
|
53
|
+
assert_raises(MalformatedCredentialError) do
|
54
|
+
auth.authenticate("test", "noway")
|
55
|
+
end
|
56
|
+
|
57
|
+
assert_raises(MalformatedCredentialError) do
|
58
|
+
auth.authenticate("test", "test")
|
59
|
+
end
|
60
|
+
|
61
|
+
time = Time.now.to_i - 1200
|
62
|
+
seed = "this is a random seed"
|
63
|
+
expired_hash = Digest::MD5.hexdigest("#{seed}:#{time}:test")
|
64
|
+
expired_cred = "#{seed}:#{time}:#{expired_hash}"
|
65
|
+
|
66
|
+
assert_raises(ExpiredCredentialError) do
|
67
|
+
auth.authenticate("test", expired_cred)
|
68
|
+
end
|
69
|
+
|
70
|
+
time = Time.now.to_i
|
71
|
+
seed = "this is a random seed"
|
72
|
+
invalid_hash = Digest::MD5.hexdigest("#{seed}:#{time}:wrong")
|
73
|
+
invalid_cred = "#{seed}:#{time}:#{expired_hash}"
|
74
|
+
|
75
|
+
assert_raises(InvalidCredentialError) do
|
76
|
+
auth.authenticate("test", invalid_cred)
|
77
|
+
end
|
78
|
+
|
79
|
+
time = Time.now.to_i
|
80
|
+
seed = "this is a random seed"
|
81
|
+
valid_hash = Digest::MD5.hexdigest("#{seed}:#{time}:test")
|
82
|
+
valid_cred = "#{seed}:#{time}:#{valid_hash}"
|
83
|
+
|
84
|
+
assert(auth.authenticate("test", valid_cred))
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_otp_login
|
88
|
+
options = {
|
89
|
+
"pwalgo" => "otp",
|
90
|
+
"authentication_realm" => "otp"
|
91
|
+
}
|
92
|
+
auth = Authenticator.getAuthenticatorByRealm(options["authentication_realm"], options)
|
93
|
+
auth << User.new("test", "test1\ntest2\ntest3\ntest4\ntest5")
|
94
|
+
assert_raises(NoSuchUserError) do
|
95
|
+
auth.authenticate("jerk", "noway")
|
96
|
+
end
|
97
|
+
|
98
|
+
assert_raises(InvalidCredentialError) do
|
99
|
+
auth.authenticate("test", "wrong")
|
100
|
+
end
|
101
|
+
|
102
|
+
1.upto(4) do |i|
|
103
|
+
assert(auth.authenticate("test","test#{i}"))
|
104
|
+
|
105
|
+
assert_raises(InvalidCredentialError) do
|
106
|
+
auth.authenticate("test", "test#{i}")
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
assert(auth.authenticate("test","test5"))
|
111
|
+
assert_raises(NoFurtherCredentialsAvailable) do
|
112
|
+
auth.authenticate("test", "test5")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
data/test/test_ftpd-memory.rb
CHANGED
@@ -9,6 +9,8 @@ end
|
|
9
9
|
require_relative 'helper'
|
10
10
|
require 'eventmachine'
|
11
11
|
require 'em-ftpd'
|
12
|
+
require 'digest/md5'
|
13
|
+
include EM::FTPD::Memory
|
12
14
|
|
13
15
|
class TestFTPDMemory < Minitest::Test
|
14
16
|
def test_example
|
@@ -18,9 +20,9 @@ class TestFTPDMemory < Minitest::Test
|
|
18
20
|
"pwalgo" => "otp",
|
19
21
|
|
20
22
|
}
|
21
|
-
auth =
|
22
|
-
auth <<
|
23
|
-
fs =
|
23
|
+
auth = Authenticator.getAuthenticatorByRealm(options["authentication_realm"], options)
|
24
|
+
auth << User.new("test", "test1\ntest2\ntest3\ntest4\ntest5")
|
25
|
+
fs = FileSystem.getFileSystem(options["filesystem_name"])
|
24
26
|
fs.create_dir("/pub")
|
25
27
|
fs.create_file("/pub/helper.rb", "test/helper.rb")
|
26
28
|
|
@@ -31,38 +33,5 @@ class TestFTPDMemory < Minitest::Test
|
|
31
33
|
end
|
32
34
|
}
|
33
35
|
end
|
34
|
-
|
35
|
-
def test_plain_login
|
36
|
-
end
|
37
|
-
|
38
|
-
def test_time_based_login
|
39
|
-
end
|
40
|
-
|
41
|
-
def test_otp_login
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_file_creation
|
45
|
-
end
|
46
|
-
|
47
|
-
def test_file_deletion
|
48
|
-
end
|
49
|
-
|
50
|
-
def test_create_directory
|
51
|
-
end
|
52
|
-
|
53
|
-
def test_delete_directory
|
54
|
-
end
|
55
|
-
|
56
|
-
def test_file_rename
|
57
|
-
end
|
58
|
-
|
59
|
-
def test_file_move_between_directories
|
60
|
-
end
|
61
|
-
|
62
|
-
def test_chmod_file
|
63
|
-
end
|
64
|
-
|
65
|
-
def test_chmod_directory
|
66
|
-
end
|
67
|
-
|
36
|
+
|
68
37
|
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
unless Kernel.respond_to?(:require_relative)
|
2
|
+
module Kernel
|
3
|
+
def require_relative(path)
|
4
|
+
require File.join(File.dirname(caller[0]), path.to_str)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
require_relative 'helper'
|
10
|
+
|
11
|
+
include EM::FTPD::Memory
|
12
|
+
|
13
|
+
class TestMemoryFilesystem < Minitest::Test
|
14
|
+
def test_filesystem_instance_retrieval
|
15
|
+
fs = FileSystem.getFileSystem(__method__)
|
16
|
+
fs2 = FileSystem.getFileSystem(__method__)
|
17
|
+
assert(fs.equal?(fs2))
|
18
|
+
FileSystem.destroyFileSystem(__method__)
|
19
|
+
fs2 = FileSystem.getFileSystem(__method__)
|
20
|
+
refute(fs.equal?(fs2))
|
21
|
+
FileSystem.destroyFileSystem(__method__)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_file_creation
|
25
|
+
fs = FileSystem.getFileSystem(__method__)
|
26
|
+
fs.create_file("/helper.rb", "test/helper.rb")
|
27
|
+
assert(fs.exist?("/helper.rb"))
|
28
|
+
refute(fs.is_dir("/helper.rb"))
|
29
|
+
assert(fs.is_file("/helper.rb"))
|
30
|
+
assert_equal(169, fs.file_size("/helper.rb"))
|
31
|
+
FileSystem.destroyFileSystem(__method__)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_file_deletion
|
35
|
+
fs = FileSystem.getFileSystem(__method__)
|
36
|
+
fs.create_file("/helper.rb", "test/helper.rb")
|
37
|
+
assert(fs.exist?("/helper.rb"))
|
38
|
+
refute(fs.is_dir("/helper.rb"))
|
39
|
+
assert(fs.is_file("/helper.rb"))
|
40
|
+
assert_equal(169, fs.file_size("/helper.rb"))
|
41
|
+
fs.delete_file("/helper.rb")
|
42
|
+
refute(fs.exist?("/helper.rb"))
|
43
|
+
FileSystem.destroyFileSystem(__method__)
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_create_directory
|
47
|
+
fs = FileSystem.getFileSystem(__method__)
|
48
|
+
fs.create_dir("/pub")
|
49
|
+
assert(fs.exist?("/pub"))
|
50
|
+
assert(fs.is_dir("/pub"))
|
51
|
+
refute(fs.is_file("/pub"))
|
52
|
+
|
53
|
+
fs.create_file("/pub/helper.rb", "test/helper.rb")
|
54
|
+
assert(fs.exist?("/pub/helper.rb"))
|
55
|
+
assert_equal(169, fs.file_size("/pub/helper.rb"))
|
56
|
+
fs.delete_file("/pub/helper.rb")
|
57
|
+
refute(fs.exist?("/pub/helper.rb"))
|
58
|
+
FileSystem.destroyFileSystem(__method__)
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_delete_directory
|
62
|
+
fs = FileSystem.getFileSystem(__method__)
|
63
|
+
fs.create_dir("/pub")
|
64
|
+
assert(fs.exist?("/pub"))
|
65
|
+
assert(fs.is_dir("/pub"))
|
66
|
+
refute(fs.is_file("/pub"))
|
67
|
+
|
68
|
+
fs.create_file("/pub/helper.rb", "test/helper.rb")
|
69
|
+
assert(fs.exist?("/pub/helper.rb"))
|
70
|
+
assert_equal(169, fs.file_size("/pub/helper.rb"))
|
71
|
+
refute(fs.delete_dir("/pub"))
|
72
|
+
fs.delete_file("/pub/helper.rb")
|
73
|
+
refute(fs.exist?("/pub/helper.rb"))
|
74
|
+
assert(fs.delete_dir("/pub"))
|
75
|
+
refute(fs.exist?("/pub"))
|
76
|
+
FileSystem.destroyFileSystem(__method__)
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_file_rename
|
80
|
+
fs = FileSystem.getFileSystem(__method__)
|
81
|
+
fs.create_dir("/pub")
|
82
|
+
assert(fs.exist?("/pub"))
|
83
|
+
assert(fs.is_dir("/pub"))
|
84
|
+
refute(fs.is_file("/pub"))
|
85
|
+
|
86
|
+
fs.create_file("/pub/helper.rb", "test/helper.rb")
|
87
|
+
assert(fs.exist?("/pub/helper.rb"))
|
88
|
+
assert_equal(169, fs.file_size("/pub/helper.rb"))
|
89
|
+
fs.rename("/pub/helper.rb", "/pub/helper.txt")
|
90
|
+
refute(fs.exist?("/pub/helper.rb"))
|
91
|
+
assert(fs.exist?("/pub/helper.txt"))
|
92
|
+
assert_equal(169, fs.file_size("/pub/helper.txt"))
|
93
|
+
|
94
|
+
FileSystem.destroyFileSystem(__method__)
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_file_move_between_directories
|
98
|
+
fs = FileSystem.getFileSystem(__method__)
|
99
|
+
fs.create_dir("/pub")
|
100
|
+
assert(fs.exist?("/pub"))
|
101
|
+
assert(fs.is_dir("/pub"))
|
102
|
+
refute(fs.is_file("/pub"))
|
103
|
+
fs.create_dir("/pub2")
|
104
|
+
assert(fs.exist?("/pub2"))
|
105
|
+
assert(fs.is_dir("/pub2"))
|
106
|
+
refute(fs.is_file("/pub2"))
|
107
|
+
|
108
|
+
fs.create_file("/pub/helper.rb", "test/helper.rb")
|
109
|
+
assert(fs.exist?("/pub/helper.rb"))
|
110
|
+
assert_equal(169, fs.file_size("/pub/helper.rb"))
|
111
|
+
fs.rename("/pub/helper.rb", "/pub2/helper.txt")
|
112
|
+
refute(fs.exist?("/pub/helper.rb"))
|
113
|
+
assert(fs.exist?("/pub2/helper.txt"))
|
114
|
+
assert_equal(169, fs.file_size("/pub2/helper.txt"))
|
115
|
+
|
116
|
+
FileSystem.destroyFileSystem(__method__)
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_rename_directory
|
120
|
+
fs = FileSystem.getFileSystem(__method__)
|
121
|
+
fs.create_dir("/pub")
|
122
|
+
assert(fs.exist?("/pub"))
|
123
|
+
assert(fs.is_dir("/pub"))
|
124
|
+
refute(fs.is_file("/pub"))
|
125
|
+
fs.create_dir("/pub2")
|
126
|
+
assert(fs.exist?("/pub2"))
|
127
|
+
assert(fs.is_dir("/pub2"))
|
128
|
+
refute(fs.is_file("/pub2"))
|
129
|
+
fs.create_file("/pub3", "test/helper.rb")
|
130
|
+
assert(fs.exist?("/pub3"))
|
131
|
+
refute(fs.is_dir("/pub3"))
|
132
|
+
assert(fs.is_file("/pub3"))
|
133
|
+
assert_equal(169, fs.file_size("/pub3"))
|
134
|
+
|
135
|
+
refute(fs.rename("/pub", "/pub2"))
|
136
|
+
refute(fs.rename("/pub", "/pub3"))
|
137
|
+
assert(fs.delete_file("/pub3"))
|
138
|
+
assert(fs.rename("/pub", "/pub3"))
|
139
|
+
|
140
|
+
FileSystem.destroyFileSystem(__method__)
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_file_permissions
|
144
|
+
fs = FileSystem.getFileSystem(__method__)
|
145
|
+
assert_raises(InvalidPermissionsError) do
|
146
|
+
fs.set_permissions("/", "rwx", "root")
|
147
|
+
end
|
148
|
+
|
149
|
+
refute(fs.set_permissions("/", "rwxr.xr.x", "nobody"))
|
150
|
+
assert(fs.set_permissions("/", "rwxr.xr.x", "root"))
|
151
|
+
refute(fs.create_dir("/pub"))
|
152
|
+
refute(fs.exist?("/pub"))
|
153
|
+
assert(fs.create_dir("/pub", "root"))
|
154
|
+
assert(fs.exist?("/pub"))
|
155
|
+
assert(fs.create_file("/pub/helper.rb", "test/helper.rb"))
|
156
|
+
assert(fs.exist?("/pub/helper.rb"))
|
157
|
+
assert(fs.delete_file("/pub/helper.rb"))
|
158
|
+
refute(fs.exist?("/pub/helper.rb"))
|
159
|
+
assert(fs.set_permissions("/pub", 'rwxr.xr.x', "root"))
|
160
|
+
refute(fs.create_file("/pub/helper.rb", "test/helper.rb"))
|
161
|
+
refute(fs.exist?("/pub/helper.rb"))
|
162
|
+
assert(fs.create_dir("/pub/pub2","root"))
|
163
|
+
assert(fs.create_dir("/pub/pub2/pub3","root"))
|
164
|
+
assert(fs.create_dir("/pub/pub2/pub3/pub4","root"))
|
165
|
+
assert(fs.set_permissions("/pub/pub2/pub3", "rwx......", "root"))
|
166
|
+
assert_equal(0, fs.list_files("/pub/pub2/pub3").length)
|
167
|
+
assert_equal(1, fs.list_files("/pub/pub2/pub3", "root").length)
|
168
|
+
refute(fs.create_file("/pub/pub2/pub3/pub4/helper.rb", "test/helper.rb"))
|
169
|
+
assert(fs.create_file("/pub/pub2/pub3/pub4/helper.rb", "test/helper.rb", "root"))
|
170
|
+
refute(fs.file_size("/pub/pub2/pub3/pub4/helper.rb"))
|
171
|
+
assert_equal(169, fs.file_size("/pub/pub2/pub3/pub4/helper.rb", "root"))
|
172
|
+
|
173
|
+
|
174
|
+
assert_equal(0, fs.list_files("/pub/pub2/pub3", "charlie").length)
|
175
|
+
refute(fs.file_size("/pub/pub2/pub3/pub4/helper.rb", "charlie"))
|
176
|
+
assert(fs.set_owner("/pub/pub2/pub3", "charlie", "root"))
|
177
|
+
assert_equal(1, fs.list_files("/pub/pub2/pub3", "charlie").length)
|
178
|
+
assert_equal(169, fs.file_size("/pub/pub2/pub3/pub4/helper.rb", "charlie"))
|
179
|
+
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-ftpd-memory
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- chrislee35
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: em-ftpd
|
@@ -98,7 +98,9 @@ files:
|
|
98
98
|
- lib/em/ftpd/memory/driver.rb
|
99
99
|
- lib/em/ftpd/memory/filesystem.rb
|
100
100
|
- test/helper.rb
|
101
|
+
- test/test_authenticator.rb
|
101
102
|
- test/test_ftpd-memory.rb
|
103
|
+
- test/test_memory_filesystem.rb
|
102
104
|
homepage: https://github.com/chrislee35/em-ftpd-memory
|
103
105
|
licenses:
|
104
106
|
- MIT
|
@@ -125,4 +127,6 @@ specification_version: 4
|
|
125
127
|
summary: Memory-based backing store for em-ftpd
|
126
128
|
test_files:
|
127
129
|
- test/helper.rb
|
130
|
+
- test/test_authenticator.rb
|
128
131
|
- test/test_ftpd-memory.rb
|
132
|
+
- test/test_memory_filesystem.rb
|