hrr_rb_sftp 0.1.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.
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: []