hrr_rb_sftp 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +25 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +7 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +135 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/demo/hrr_rb_sftp_server.rb +23 -0
  13. data/demo/instantiate_hrr_rb_sftp_server.rb +67 -0
  14. data/demo/spawn_hrr_rb_sftp_server.rb +66 -0
  15. data/hrr_rb_sftp.gemspec +26 -0
  16. data/lib/hrr_rb_sftp.rb +13 -0
  17. data/lib/hrr_rb_sftp/loggable.rb +41 -0
  18. data/lib/hrr_rb_sftp/protocol.rb +62 -0
  19. data/lib/hrr_rb_sftp/protocol/common.rb +10 -0
  20. data/lib/hrr_rb_sftp/protocol/common/data_type.rb +15 -0
  21. data/lib/hrr_rb_sftp/protocol/common/data_type/byte.rb +22 -0
  22. data/lib/hrr_rb_sftp/protocol/common/data_type/extension_pair.rb +23 -0
  23. data/lib/hrr_rb_sftp/protocol/common/data_type/extension_pairs.rb +24 -0
  24. data/lib/hrr_rb_sftp/protocol/common/data_type/string.rb +24 -0
  25. data/lib/hrr_rb_sftp/protocol/common/data_type/uint32.rb +22 -0
  26. data/lib/hrr_rb_sftp/protocol/common/data_type/uint64.rb +22 -0
  27. data/lib/hrr_rb_sftp/protocol/common/packet.rb +11 -0
  28. data/lib/hrr_rb_sftp/protocol/common/packet/001_ssh_fxp_init.rb +18 -0
  29. data/lib/hrr_rb_sftp/protocol/common/packet/002_ssh_fxp_version.rb +19 -0
  30. data/lib/hrr_rb_sftp/protocol/common/packetable.rb +72 -0
  31. data/lib/hrr_rb_sftp/protocol/version1.rb +10 -0
  32. data/lib/hrr_rb_sftp/protocol/version1/data_type.rb +11 -0
  33. data/lib/hrr_rb_sftp/protocol/version1/data_type/attrs.rb +54 -0
  34. data/lib/hrr_rb_sftp/protocol/version1/packet.rb +29 -0
  35. data/lib/hrr_rb_sftp/protocol/version1/packet/003_ssh_fxp_open.rb +109 -0
  36. data/lib/hrr_rb_sftp/protocol/version1/packet/004_ssh_fxp_close.rb +44 -0
  37. data/lib/hrr_rb_sftp/protocol/version1/packet/005_ssh_fxp_read.rb +53 -0
  38. data/lib/hrr_rb_sftp/protocol/version1/packet/006_ssh_fxp_write.rb +46 -0
  39. data/lib/hrr_rb_sftp/protocol/version1/packet/007_ssh_fxp_lstat.rb +62 -0
  40. data/lib/hrr_rb_sftp/protocol/version1/packet/008_ssh_fxp_fstat.rb +48 -0
  41. data/lib/hrr_rb_sftp/protocol/version1/packet/009_ssh_fxp_setstat.rb +63 -0
  42. data/lib/hrr_rb_sftp/protocol/version1/packet/010_ssh_fxp_fsetstat.rb +48 -0
  43. data/lib/hrr_rb_sftp/protocol/version1/packet/011_ssh_fxp_opendir.rb +65 -0
  44. data/lib/hrr_rb_sftp/protocol/version1/packet/012_ssh_fxp_readdir.rb +134 -0
  45. data/lib/hrr_rb_sftp/protocol/version1/packet/013_ssh_fxp_remove.rb +57 -0
  46. data/lib/hrr_rb_sftp/protocol/version1/packet/014_ssh_fxp_mkdir.rb +57 -0
  47. data/lib/hrr_rb_sftp/protocol/version1/packet/015_ssh_fxp_rmdir.rb +73 -0
  48. data/lib/hrr_rb_sftp/protocol/version1/packet/016_ssh_fxp_realpath.rb +30 -0
  49. data/lib/hrr_rb_sftp/protocol/version1/packet/017_ssh_fxp_stat.rb +62 -0
  50. data/lib/hrr_rb_sftp/protocol/version1/packet/101_ssh_fxp_status.rb +29 -0
  51. data/lib/hrr_rb_sftp/protocol/version1/packet/102_ssh_fxp_handle.rb +19 -0
  52. data/lib/hrr_rb_sftp/protocol/version1/packet/103_ssh_fxp_data.rb +19 -0
  53. data/lib/hrr_rb_sftp/protocol/version1/packet/104_ssh_fxp_name.rb +33 -0
  54. data/lib/hrr_rb_sftp/protocol/version1/packet/105_ssh_fxp_attrs.rb +19 -0
  55. data/lib/hrr_rb_sftp/protocol/version2.rb +10 -0
  56. data/lib/hrr_rb_sftp/protocol/version2/data_type.rb +9 -0
  57. data/lib/hrr_rb_sftp/protocol/version2/packet.rb +11 -0
  58. data/lib/hrr_rb_sftp/protocol/version2/packet/018_ssh_fxp_rename.rb +70 -0
  59. data/lib/hrr_rb_sftp/protocol/version3.rb +10 -0
  60. data/lib/hrr_rb_sftp/protocol/version3/data_type.rb +9 -0
  61. data/lib/hrr_rb_sftp/protocol/version3/packet.rb +16 -0
  62. data/lib/hrr_rb_sftp/protocol/version3/packet/014_ssh_fxp_mkdir.rb +58 -0
  63. data/lib/hrr_rb_sftp/protocol/version3/packet/019_ssh_fxp_readlink.rb +57 -0
  64. data/lib/hrr_rb_sftp/protocol/version3/packet/020_ssh_fxp_symlink.rb +58 -0
  65. data/lib/hrr_rb_sftp/protocol/version3/packet/101_ssh_fxp_status.rb +31 -0
  66. data/lib/hrr_rb_sftp/protocol/version3/packet/200_ssh_fxp_extended.rb +34 -0
  67. data/lib/hrr_rb_sftp/protocol/version3/packet/201_ssh_fxp_extended_reply.rb +23 -0
  68. data/lib/hrr_rb_sftp/receiver.rb +22 -0
  69. data/lib/hrr_rb_sftp/sender.rb +13 -0
  70. data/lib/hrr_rb_sftp/server.rb +96 -0
  71. data/lib/hrr_rb_sftp/version.rb +3 -0
  72. metadata +114 -0
@@ -0,0 +1,58 @@
1
+ module HrrRbSftp
2
+ class Protocol
3
+ class Version3
4
+ module Packet
5
+ class SSH_FXP_SYMLINK
6
+ include Common::Packetable
7
+
8
+ TYPE = 20
9
+
10
+ FORMAT = [
11
+ [DataType::Byte, :"type" ],
12
+ [DataType::Uint32, :"request-id"],
13
+ [DataType::String, :"linkpath" ],
14
+ [DataType::String, :"targetpath"],
15
+ ]
16
+
17
+ def respond_to request
18
+ begin
19
+ File.symlink request[:"targetpath"], request[:"linkpath"]
20
+ {
21
+ :"type" => Packet::SSH_FXP_STATUS::TYPE,
22
+ :"request-id" => request[:"request-id"],
23
+ :"code" => Packet::SSH_FXP_STATUS::SSH_FX_OK,
24
+ :"error message" => "Success",
25
+ :"language tag" => "",
26
+ }
27
+ rescue Errno::EACCES
28
+ {
29
+ :"type" => Packet::SSH_FXP_STATUS::TYPE,
30
+ :"request-id" => request[:"request-id"],
31
+ :"code" => Packet::SSH_FXP_STATUS::SSH_FX_PERMISSION_DENIED,
32
+ :"error message" => "Permission denied",
33
+ :"language tag" => "",
34
+ }
35
+ rescue Errno::EEXIST
36
+ {
37
+ :"type" => Packet::SSH_FXP_STATUS::TYPE,
38
+ :"request-id" => request[:"request-id"],
39
+ :"code" => Packet::SSH_FXP_STATUS::SSH_FX_FAILURE,
40
+ :"error message" => "File exists",
41
+ :"language tag" => "",
42
+ }
43
+ rescue => e
44
+ log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
45
+ {
46
+ :"type" => Packet::SSH_FXP_STATUS::TYPE,
47
+ :"request-id" => request[:"request-id"],
48
+ :"code" => Packet::SSH_FXP_STATUS::SSH_FX_FAILURE,
49
+ :"error message" => e.message,
50
+ :"language tag" => "",
51
+ }
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,31 @@
1
+ module HrrRbSftp
2
+ class Protocol
3
+ class Version3
4
+ module Packet
5
+ class SSH_FXP_STATUS
6
+ include Common::Packetable
7
+
8
+ TYPE = 101
9
+
10
+ FORMAT = [
11
+ [DataType::Byte, :"type" ],
12
+ [DataType::Uint32, :"request-id" ],
13
+ [DataType::Uint32, :"code" ],
14
+ [DataType::String, :"error message"],
15
+ [DataType::String, :"language tag" ],
16
+ ]
17
+
18
+ SSH_FX_OK = 0
19
+ SSH_FX_EOF = 1
20
+ SSH_FX_NO_SUCH_FILE = 2
21
+ SSH_FX_PERMISSION_DENIED = 3
22
+ SSH_FX_FAILURE = 4
23
+ SSH_FX_BAD_MESSAGE = 5
24
+ SSH_FX_NO_CONNECTION = 6
25
+ SSH_FX_CONNECTION_LOST = 7
26
+ SSH_FX_OP_UNSUPPORTED = 8
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,34 @@
1
+ module HrrRbSftp
2
+ class Protocol
3
+ class Version3
4
+ module Packet
5
+ class SSH_FXP_EXTENDED
6
+ include Common::Packetable
7
+
8
+ TYPE = 200
9
+
10
+ FORMAT = [
11
+ [DataType::Byte, :"type" ],
12
+ [DataType::Uint32, :"request-id" ],
13
+ [DataType::String, :"extended-request"],
14
+ ]
15
+
16
+ CONDITIONAL_FORMAT = {
17
+ :"extended-request" => {
18
+ },
19
+ }
20
+
21
+ def respond_to request
22
+ {
23
+ :"type" => Packet::SSH_FXP_STATUS::TYPE,
24
+ :"request-id" => request[:"request-id"],
25
+ :"code" => Packet::SSH_FXP_STATUS::SSH_FX_OP_UNSUPPORTED,
26
+ :"error message" => "Unsupported extended-request: #{request[:"extended-request"]}",
27
+ :"language tag" => "",
28
+ }
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,23 @@
1
+ module HrrRbSftp
2
+ class Protocol
3
+ class Version3
4
+ module Packet
5
+ class SSH_FXP_EXTENDED_REPLY
6
+ include Common::Packetable
7
+
8
+ TYPE = 201
9
+
10
+ FORMAT = [
11
+ [DataType::Byte, :"type" ],
12
+ [DataType::Uint32, :"request-id"],
13
+ ]
14
+
15
+ CONDITIONAL_FORMAT = {
16
+ :"extended-request" => {
17
+ },
18
+ }
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ module HrrRbSftp
2
+ class Receiver
3
+ def initialize io_in
4
+ @io_in = io_in
5
+ end
6
+
7
+ def receive
8
+ begin
9
+ paylaod_length = Protocol::Common::DataType::Uint32.decode(@io_in)
10
+ rescue NoMethodError
11
+ nil
12
+ else
13
+ payload = @io_in.read(paylaod_length)
14
+ if payload.nil? || payload.length != paylaod_length
15
+ nil
16
+ else
17
+ payload
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ module HrrRbSftp
2
+ class Sender
3
+ def initialize io_out
4
+ @io_out = io_out
5
+ end
6
+
7
+ def send payload
8
+ @io_out.write(Protocol::Common::DataType::Uint32.encode(payload.length))
9
+ @io_out.write(payload)
10
+ @io_out.flush
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,96 @@
1
+ module HrrRbSftp
2
+ class Server
3
+ include Loggable
4
+
5
+ def initialize logger: nil
6
+ self.logger = logger
7
+ end
8
+
9
+ def start io_in, io_out, io_err
10
+ log_info { "start server" }
11
+
12
+ @io_in = io_in
13
+ @io_out = io_out
14
+ @io_err = io_err
15
+
16
+ @receiver = Receiver.new(@io_in)
17
+ @sender = Sender.new(@io_out)
18
+
19
+ @version = negotiate_version
20
+
21
+ @protocol = Protocol.new(@version, logger: logger)
22
+
23
+ begin
24
+ respond_to_requests
25
+ rescue => e
26
+ log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
27
+ raise
28
+ ensure
29
+ close_handles
30
+ end
31
+
32
+ log_info { "server finished" }
33
+ end
34
+
35
+ private
36
+
37
+ def negotiate_version
38
+ log_info { "start negotiate_version" }
39
+
40
+ remote_version = receive_fxp_init
41
+ log_info { "remote version: #{remote_version}" }
42
+
43
+ local_version = Protocol.versions.max
44
+ log_info { "local version: #{local_version}" }
45
+
46
+ version = [remote_version, local_version].min
47
+ log_info { "negotiated version: #{version}" }
48
+
49
+ send_fxp_version version
50
+
51
+ version
52
+ end
53
+
54
+ def receive_fxp_init
55
+ log_debug { "start receive_fxp_init" }
56
+
57
+ payload = @receiver.receive
58
+
59
+ if payload.nil?
60
+ raise "Failed receiving SSH_FXP_INIT"
61
+ end
62
+
63
+ packet = Protocol::Common::Packet::SSH_FXP_INIT.new({}, logger: logger).decode payload
64
+ packet[:"version"]
65
+ end
66
+
67
+ def send_fxp_version version
68
+ log_debug { "start send_fxp_version" }
69
+
70
+ packet = {
71
+ :"type" => Protocol::Common::Packet::SSH_FXP_VERSION::TYPE,
72
+ :"version" => version,
73
+ :"extensions" => [],
74
+ }
75
+ payload = Protocol::Common::Packet::SSH_FXP_VERSION.new({}, logger: logger).encode packet
76
+ @sender.send payload
77
+ end
78
+
79
+ def respond_to_requests
80
+ log_info { "start respond_to_requests" }
81
+
82
+ log_info { "start request and response loop" }
83
+ while request = @receiver.receive
84
+ response = @protocol.respond_to request
85
+ @sender.send response
86
+ end
87
+ log_info { "request and response loop finished" }
88
+ end
89
+
90
+ def close_handles
91
+ log_info { "closing handles" }
92
+ @protocol.close_handles
93
+ log_info { "handles closed" }
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,3 @@
1
+ module HrrRbSftp
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hrr_rb_sftp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - hirura
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-06-07 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Pure Ruby SFTP server implementation.
14
+ email:
15
+ - hirura@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".gitignore"
21
+ - ".rspec"
22
+ - ".travis.yml"
23
+ - CODE_OF_CONDUCT.md
24
+ - Gemfile
25
+ - LICENSE.txt
26
+ - README.md
27
+ - Rakefile
28
+ - bin/console
29
+ - bin/setup
30
+ - demo/hrr_rb_sftp_server.rb
31
+ - demo/instantiate_hrr_rb_sftp_server.rb
32
+ - demo/spawn_hrr_rb_sftp_server.rb
33
+ - hrr_rb_sftp.gemspec
34
+ - lib/hrr_rb_sftp.rb
35
+ - lib/hrr_rb_sftp/loggable.rb
36
+ - lib/hrr_rb_sftp/protocol.rb
37
+ - lib/hrr_rb_sftp/protocol/common.rb
38
+ - lib/hrr_rb_sftp/protocol/common/data_type.rb
39
+ - lib/hrr_rb_sftp/protocol/common/data_type/byte.rb
40
+ - lib/hrr_rb_sftp/protocol/common/data_type/extension_pair.rb
41
+ - lib/hrr_rb_sftp/protocol/common/data_type/extension_pairs.rb
42
+ - lib/hrr_rb_sftp/protocol/common/data_type/string.rb
43
+ - lib/hrr_rb_sftp/protocol/common/data_type/uint32.rb
44
+ - lib/hrr_rb_sftp/protocol/common/data_type/uint64.rb
45
+ - lib/hrr_rb_sftp/protocol/common/packet.rb
46
+ - lib/hrr_rb_sftp/protocol/common/packet/001_ssh_fxp_init.rb
47
+ - lib/hrr_rb_sftp/protocol/common/packet/002_ssh_fxp_version.rb
48
+ - lib/hrr_rb_sftp/protocol/common/packetable.rb
49
+ - lib/hrr_rb_sftp/protocol/version1.rb
50
+ - lib/hrr_rb_sftp/protocol/version1/data_type.rb
51
+ - lib/hrr_rb_sftp/protocol/version1/data_type/attrs.rb
52
+ - lib/hrr_rb_sftp/protocol/version1/packet.rb
53
+ - lib/hrr_rb_sftp/protocol/version1/packet/003_ssh_fxp_open.rb
54
+ - lib/hrr_rb_sftp/protocol/version1/packet/004_ssh_fxp_close.rb
55
+ - lib/hrr_rb_sftp/protocol/version1/packet/005_ssh_fxp_read.rb
56
+ - lib/hrr_rb_sftp/protocol/version1/packet/006_ssh_fxp_write.rb
57
+ - lib/hrr_rb_sftp/protocol/version1/packet/007_ssh_fxp_lstat.rb
58
+ - lib/hrr_rb_sftp/protocol/version1/packet/008_ssh_fxp_fstat.rb
59
+ - lib/hrr_rb_sftp/protocol/version1/packet/009_ssh_fxp_setstat.rb
60
+ - lib/hrr_rb_sftp/protocol/version1/packet/010_ssh_fxp_fsetstat.rb
61
+ - lib/hrr_rb_sftp/protocol/version1/packet/011_ssh_fxp_opendir.rb
62
+ - lib/hrr_rb_sftp/protocol/version1/packet/012_ssh_fxp_readdir.rb
63
+ - lib/hrr_rb_sftp/protocol/version1/packet/013_ssh_fxp_remove.rb
64
+ - lib/hrr_rb_sftp/protocol/version1/packet/014_ssh_fxp_mkdir.rb
65
+ - lib/hrr_rb_sftp/protocol/version1/packet/015_ssh_fxp_rmdir.rb
66
+ - lib/hrr_rb_sftp/protocol/version1/packet/016_ssh_fxp_realpath.rb
67
+ - lib/hrr_rb_sftp/protocol/version1/packet/017_ssh_fxp_stat.rb
68
+ - lib/hrr_rb_sftp/protocol/version1/packet/101_ssh_fxp_status.rb
69
+ - lib/hrr_rb_sftp/protocol/version1/packet/102_ssh_fxp_handle.rb
70
+ - lib/hrr_rb_sftp/protocol/version1/packet/103_ssh_fxp_data.rb
71
+ - lib/hrr_rb_sftp/protocol/version1/packet/104_ssh_fxp_name.rb
72
+ - lib/hrr_rb_sftp/protocol/version1/packet/105_ssh_fxp_attrs.rb
73
+ - lib/hrr_rb_sftp/protocol/version2.rb
74
+ - lib/hrr_rb_sftp/protocol/version2/data_type.rb
75
+ - lib/hrr_rb_sftp/protocol/version2/packet.rb
76
+ - lib/hrr_rb_sftp/protocol/version2/packet/018_ssh_fxp_rename.rb
77
+ - lib/hrr_rb_sftp/protocol/version3.rb
78
+ - lib/hrr_rb_sftp/protocol/version3/data_type.rb
79
+ - lib/hrr_rb_sftp/protocol/version3/packet.rb
80
+ - lib/hrr_rb_sftp/protocol/version3/packet/014_ssh_fxp_mkdir.rb
81
+ - lib/hrr_rb_sftp/protocol/version3/packet/019_ssh_fxp_readlink.rb
82
+ - lib/hrr_rb_sftp/protocol/version3/packet/020_ssh_fxp_symlink.rb
83
+ - lib/hrr_rb_sftp/protocol/version3/packet/101_ssh_fxp_status.rb
84
+ - lib/hrr_rb_sftp/protocol/version3/packet/200_ssh_fxp_extended.rb
85
+ - lib/hrr_rb_sftp/protocol/version3/packet/201_ssh_fxp_extended_reply.rb
86
+ - lib/hrr_rb_sftp/receiver.rb
87
+ - lib/hrr_rb_sftp/sender.rb
88
+ - lib/hrr_rb_sftp/server.rb
89
+ - lib/hrr_rb_sftp/version.rb
90
+ homepage: https://github.com/hirura/hrr_rb_sftp
91
+ licenses:
92
+ - MIT
93
+ metadata:
94
+ homepage_uri: https://github.com/hirura/hrr_rb_sftp
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 2.0.0
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubygems_version: 3.1.3
111
+ signing_key:
112
+ specification_version: 4
113
+ summary: Pure Ruby SFTP server implementation.
114
+ test_files: []