hrr_rb_sftp 0.1.0 → 0.2.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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +23 -0
  3. data/lib/hrr_rb_sftp.rb +79 -1
  4. data/lib/hrr_rb_sftp/loggable.rb +34 -0
  5. data/lib/hrr_rb_sftp/protocol.rb +39 -33
  6. data/lib/hrr_rb_sftp/protocol/common.rb +6 -3
  7. data/lib/hrr_rb_sftp/protocol/common/data_types.rb +19 -0
  8. data/lib/hrr_rb_sftp/protocol/common/data_types/byte.rb +40 -0
  9. data/lib/hrr_rb_sftp/protocol/common/data_types/extension_pair.rb +41 -0
  10. data/lib/hrr_rb_sftp/protocol/common/data_types/extension_pairs.rb +42 -0
  11. data/lib/hrr_rb_sftp/protocol/common/data_types/string.rb +42 -0
  12. data/lib/hrr_rb_sftp/protocol/common/data_types/uint32.rb +40 -0
  13. data/lib/hrr_rb_sftp/protocol/common/data_types/uint64.rb +40 -0
  14. data/lib/hrr_rb_sftp/protocol/common/packets.rb +16 -0
  15. data/lib/hrr_rb_sftp/protocol/common/packets/001_ssh_fxp_init.rb +27 -0
  16. data/lib/hrr_rb_sftp/protocol/common/packets/002_ssh_fxp_version.rb +28 -0
  17. data/lib/hrr_rb_sftp/protocol/common/packets/packet.rb +96 -0
  18. data/lib/hrr_rb_sftp/protocol/version1.rb +11 -3
  19. data/lib/hrr_rb_sftp/protocol/version1/data_types.rb +15 -0
  20. data/lib/hrr_rb_sftp/protocol/version1/data_types/attrs.rb +91 -0
  21. data/lib/hrr_rb_sftp/protocol/version1/packets.rb +72 -0
  22. data/lib/hrr_rb_sftp/protocol/version1/{packet → packets}/003_ssh_fxp_open.rb +94 -43
  23. data/lib/hrr_rb_sftp/protocol/version1/packets/004_ssh_fxp_close.rb +61 -0
  24. data/lib/hrr_rb_sftp/protocol/version1/packets/005_ssh_fxp_read.rb +72 -0
  25. data/lib/hrr_rb_sftp/protocol/version1/packets/006_ssh_fxp_write.rb +64 -0
  26. data/lib/hrr_rb_sftp/protocol/version1/{packet → packets}/007_ssh_fxp_lstat.rb +27 -9
  27. data/lib/hrr_rb_sftp/protocol/version1/{packet → packets}/008_ssh_fxp_fstat.rb +26 -9
  28. data/lib/hrr_rb_sftp/protocol/version1/packets/009_ssh_fxp_setstat.rb +92 -0
  29. data/lib/hrr_rb_sftp/protocol/version1/packets/010_ssh_fxp_fsetstat.rb +85 -0
  30. data/lib/hrr_rb_sftp/protocol/version1/{packet → packets}/011_ssh_fxp_opendir.rb +32 -11
  31. data/lib/hrr_rb_sftp/protocol/version1/{packet → packets}/012_ssh_fxp_readdir.rb +73 -49
  32. data/lib/hrr_rb_sftp/protocol/version1/{packet → packets}/013_ssh_fxp_remove.rb +27 -9
  33. data/lib/hrr_rb_sftp/protocol/version1/{packet → packets}/014_ssh_fxp_mkdir.rb +28 -10
  34. data/lib/hrr_rb_sftp/protocol/version1/{packet → packets}/015_ssh_fxp_rmdir.rb +32 -12
  35. data/lib/hrr_rb_sftp/protocol/version1/packets/016_ssh_fxp_realpath.rb +47 -0
  36. data/lib/hrr_rb_sftp/protocol/version1/{packet → packets}/017_ssh_fxp_stat.rb +27 -9
  37. data/lib/hrr_rb_sftp/protocol/version1/packets/101_ssh_fxp_status.rb +73 -0
  38. data/lib/hrr_rb_sftp/protocol/version1/packets/102_ssh_fxp_handle.rb +28 -0
  39. data/lib/hrr_rb_sftp/protocol/version1/packets/103_ssh_fxp_data.rb +28 -0
  40. data/lib/hrr_rb_sftp/protocol/version1/packets/104_ssh_fxp_name.rb +48 -0
  41. data/lib/hrr_rb_sftp/protocol/version1/packets/105_ssh_fxp_attrs.rb +28 -0
  42. data/lib/hrr_rb_sftp/protocol/version1/packets/packet.rb +57 -0
  43. data/lib/hrr_rb_sftp/protocol/version2.rb +11 -3
  44. data/lib/hrr_rb_sftp/protocol/version2/data_types.rb +13 -0
  45. data/lib/hrr_rb_sftp/protocol/version2/packets.rb +14 -0
  46. data/lib/hrr_rb_sftp/protocol/version2/packets/018_ssh_fxp_rename.rb +91 -0
  47. data/lib/hrr_rb_sftp/protocol/version3.rb +12 -3
  48. data/lib/hrr_rb_sftp/protocol/version3/data_types.rb +13 -0
  49. data/lib/hrr_rb_sftp/protocol/version3/extensions.rb +94 -0
  50. data/lib/hrr_rb_sftp/protocol/version3/extensions/extension.rb +58 -0
  51. data/lib/hrr_rb_sftp/protocol/version3/extensions/fsync_at_openssh_com.rb +59 -0
  52. data/lib/hrr_rb_sftp/protocol/version3/extensions/hardlink_at_openssh_com.rb +84 -0
  53. data/lib/hrr_rb_sftp/protocol/version3/extensions/lsetstat_at_openssh_com.rb +132 -0
  54. data/lib/hrr_rb_sftp/protocol/version3/extensions/posix_rename_at_openssh_com.rb +76 -0
  55. data/lib/hrr_rb_sftp/protocol/version3/packets.rb +19 -0
  56. data/lib/hrr_rb_sftp/protocol/version3/packets/014_ssh_fxp_mkdir.rb +75 -0
  57. data/lib/hrr_rb_sftp/protocol/version3/packets/019_ssh_fxp_readlink.rb +76 -0
  58. data/lib/hrr_rb_sftp/protocol/version3/packets/020_ssh_fxp_symlink.rb +76 -0
  59. data/lib/hrr_rb_sftp/protocol/version3/packets/101_ssh_fxp_status.rb +25 -0
  60. data/lib/hrr_rb_sftp/protocol/version3/packets/200_ssh_fxp_extended.rb +95 -0
  61. data/lib/hrr_rb_sftp/protocol/version3/packets/201_ssh_fxp_extended_reply.rb +60 -0
  62. data/lib/hrr_rb_sftp/receiver.rb +17 -2
  63. data/lib/hrr_rb_sftp/sender.rb +15 -1
  64. data/lib/hrr_rb_sftp/server.rb +43 -12
  65. data/lib/hrr_rb_sftp/version.rb +5 -1
  66. metadata +54 -47
  67. data/lib/hrr_rb_sftp/protocol/common/data_type.rb +0 -15
  68. data/lib/hrr_rb_sftp/protocol/common/data_type/byte.rb +0 -22
  69. data/lib/hrr_rb_sftp/protocol/common/data_type/extension_pair.rb +0 -23
  70. data/lib/hrr_rb_sftp/protocol/common/data_type/extension_pairs.rb +0 -24
  71. data/lib/hrr_rb_sftp/protocol/common/data_type/string.rb +0 -24
  72. data/lib/hrr_rb_sftp/protocol/common/data_type/uint32.rb +0 -22
  73. data/lib/hrr_rb_sftp/protocol/common/data_type/uint64.rb +0 -22
  74. data/lib/hrr_rb_sftp/protocol/common/packet.rb +0 -11
  75. data/lib/hrr_rb_sftp/protocol/common/packet/001_ssh_fxp_init.rb +0 -18
  76. data/lib/hrr_rb_sftp/protocol/common/packet/002_ssh_fxp_version.rb +0 -19
  77. data/lib/hrr_rb_sftp/protocol/common/packetable.rb +0 -72
  78. data/lib/hrr_rb_sftp/protocol/version1/data_type.rb +0 -11
  79. data/lib/hrr_rb_sftp/protocol/version1/data_type/attrs.rb +0 -54
  80. data/lib/hrr_rb_sftp/protocol/version1/packet.rb +0 -29
  81. data/lib/hrr_rb_sftp/protocol/version1/packet/004_ssh_fxp_close.rb +0 -44
  82. data/lib/hrr_rb_sftp/protocol/version1/packet/005_ssh_fxp_read.rb +0 -53
  83. data/lib/hrr_rb_sftp/protocol/version1/packet/006_ssh_fxp_write.rb +0 -46
  84. data/lib/hrr_rb_sftp/protocol/version1/packet/009_ssh_fxp_setstat.rb +0 -63
  85. data/lib/hrr_rb_sftp/protocol/version1/packet/010_ssh_fxp_fsetstat.rb +0 -48
  86. data/lib/hrr_rb_sftp/protocol/version1/packet/016_ssh_fxp_realpath.rb +0 -30
  87. data/lib/hrr_rb_sftp/protocol/version1/packet/101_ssh_fxp_status.rb +0 -29
  88. data/lib/hrr_rb_sftp/protocol/version1/packet/102_ssh_fxp_handle.rb +0 -19
  89. data/lib/hrr_rb_sftp/protocol/version1/packet/103_ssh_fxp_data.rb +0 -19
  90. data/lib/hrr_rb_sftp/protocol/version1/packet/104_ssh_fxp_name.rb +0 -33
  91. data/lib/hrr_rb_sftp/protocol/version1/packet/105_ssh_fxp_attrs.rb +0 -19
  92. data/lib/hrr_rb_sftp/protocol/version2/data_type.rb +0 -9
  93. data/lib/hrr_rb_sftp/protocol/version2/packet.rb +0 -11
  94. data/lib/hrr_rb_sftp/protocol/version2/packet/018_ssh_fxp_rename.rb +0 -70
  95. data/lib/hrr_rb_sftp/protocol/version3/data_type.rb +0 -9
  96. data/lib/hrr_rb_sftp/protocol/version3/packet.rb +0 -16
  97. data/lib/hrr_rb_sftp/protocol/version3/packet/014_ssh_fxp_mkdir.rb +0 -58
  98. data/lib/hrr_rb_sftp/protocol/version3/packet/019_ssh_fxp_readlink.rb +0 -57
  99. data/lib/hrr_rb_sftp/protocol/version3/packet/020_ssh_fxp_symlink.rb +0 -58
  100. data/lib/hrr_rb_sftp/protocol/version3/packet/101_ssh_fxp_status.rb +0 -31
  101. data/lib/hrr_rb_sftp/protocol/version3/packet/200_ssh_fxp_extended.rb +0 -34
  102. data/lib/hrr_rb_sftp/protocol/version3/packet/201_ssh_fxp_extended_reply.rb +0 -23
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 836dd45879b224d1b99e0584fa6dfb374d51ddb77cbd90dbb08c2697aed1e8b4
4
- data.tar.gz: 68dccfef0acb49b3576ef35fe500c8669e213d5b732ebdac34d3ab54ebba3953
3
+ metadata.gz: 6abfc35304fc1fc0475db003dd172814dc2a1e2308f811efdc9e527b8abebfb3
4
+ data.tar.gz: 38d78a957ea3650ca0942e6425179dec884b9497fa0f8466dd14eaa2daba149e
5
5
  SHA512:
6
- metadata.gz: cf36e84da8b26837ad259906b8d6340ed1cfc5e7e0ed3c88c1bd93555d8ab9964321504d40971b26e8cfae48808492389964bf5ffc706bbd4012c1adee1749ff
7
- data.tar.gz: 87ef0bfbefdfc259747eecfce36cf7bcef3a07729380b1c827907f62cc64fe5b1065092f5ab65f41622b64afba0dac7744c73d6a69f4410001e65af64159b7c0
6
+ metadata.gz: '082c34d8f7976f2a5443d5a93782c3265541f43e894afaf93ae7230ab9f6d6ef010323752aa83d66ea62c30f53c1df5d1adc9e1e7ab826dad285461dabf65817'
7
+ data.tar.gz: 87e00e812bf6bea182e6641860cd7a2422f1d7c333881df826e686a570756ee4653d2d51a663383ee027100303e0ea0c78aa251ca9316a2a024e566086fa36ab
data/README.md CHANGED
@@ -13,6 +13,8 @@ hrr_rb_sftp can be run on SSH 2.0 server like OpenSSH or [hrr_rb_ssh](https://gi
13
13
  - [Usage](#usage)
14
14
  - [hrr\_rb\_ssh's SFTP subsystem](#hrr_rb_sshs-sftp-subsystem)
15
15
  - [OpenSSH's SFTP subsystem](#opensshs-sftp-subsystem)
16
+ - [Note](#note)
17
+ - [Supported extensions](#supported-extensions)
16
18
  - [Development](#development)
17
19
  - [Contributing](#contributing)
18
20
  - [License](#license)
@@ -115,6 +117,27 @@ hrr_rb_sftp can be an alternative with replacing the line in the config file. (A
115
117
 
116
118
  Where, the /path/to/hrr_rb_sftp_server.rb code is the same as shown above.
117
119
 
120
+ ## Note
121
+
122
+ - Reversal of SSH_FXP_SYMLINK arguments
123
+ Because OpenSSH's sftp-server implementation takes SSH_FXP_SYMLINK request linkpath and targetpath arguments in reverse order, this library follows it.
124
+ The SSH_FXP_SYMLINK request format is as follows:
125
+
126
+ ```
127
+ uint32 id
128
+ string targetpath
129
+ string linkpath
130
+ ```
131
+
132
+ ## Supported extensions
133
+
134
+ The following extensions are supported.
135
+
136
+ - hardlink@openssh.com version 1
137
+ - fsync@openssh.com version 1
138
+ - posix-rename@openssh.com version 1
139
+ - lsetstat@openssh.com version 1
140
+
118
141
  ## Development
119
142
 
120
143
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -1,7 +1,85 @@
1
+ #
2
+ # hrr_rb_sftp is a pure Ruby SFTP server implementation.
3
+ # hrr_rb_sftp now supports SFTP protocol version 1, 2, and 3.
4
+ # hrr_rb_sftp can be run on SSH 2.0 server like OpenSSH or hrr_rb_ssh.
5
+ #
6
+ # It is straightforward to implement SFTP server on SSH 2.0 server library written in Ruby like hrr_rb_ssh.
7
+ # There are two ways to work with hrr_rb_ssh, on same process or spawning child process.
8
+ # On both cases, hrr_rb_ssh's request handler mechanism is used.
9
+ #
10
+ # To run hrr_rb_sftp server on the same process that hrr_rb_ssh is running, instantiate and start the hrr_rb_sftp server in a sftp subsystem request.
11
+ # On the other hand, because the arguments for the hrr_rb_sftp server can be standard input, output, and error, so hrr_rb_sftp can be a independent program and be spawned as a child process.
12
+ #
13
+ # OpenSSH has capability to run user-defined subsystems. Subsystems that the OpenSSH server recognizes are listed in /etc/ssh/sshd_config file.
14
+ # Usually SFTP subsystem is defined by default to use OpenSSH's SFTP server implementation.
15
+ # hrr_rb_sftp can be an alternative with replacing the line in the config file. (After editing the config, reloading or restarting sshd is required.)
16
+ #
17
+ # The following extensions are supported.
18
+ # - hardlink@openssh.com
19
+ # - fsync@openssh.com
20
+ # - posix-rename@openssh.com
21
+ # - lsetstat@openssh.com
22
+ #
23
+ # @note
24
+ # - Reversal of SSH_FXP_SYMLINK arguments
25
+ # Because OpenSSH's sftp-server implementation takes SSH_FXP_SYMLINK request linkpath and targetpath arguments in reverse order, this library follows it.
26
+ # The SSH_FXP_SYMLINK request format is as follows:
27
+ #
28
+ # uint32 id
29
+ # string targetpath
30
+ # string linkpath
31
+ #
32
+ # @example On the same process that hrr_rb_ssh is running
33
+ # subsys = HrrRbSsh::Connection::RequestHandler.new { |ctx|
34
+ # ctx.chain_proc { |chain|
35
+ # case ctx.subsystem_name
36
+ # when 'sftp'
37
+ # begin
38
+ # sftp_server = HrrRbSftp::Server.new(logger: nil)
39
+ # sftp_server.start(ctx.io[0], ctx.io[1], ctx.io[2])
40
+ # exitstatus = 0
41
+ # rescue
42
+ # exitstatus = 1
43
+ # end
44
+ # else
45
+ # # Do something for other subsystem, or just return exitstatus
46
+ # exitstatus = 0
47
+ # end
48
+ # exitstatus
49
+ # }
50
+ # }
51
+ # options['connection_channel_request_subsystem'] = subsys
52
+ #
53
+ # @example Spawnning SFTP server process
54
+ # subsys = HrrRbSsh::Connection::RequestHandler.new { |ctx|
55
+ # ctx.chain_proc { |chain|
56
+ # case ctx.subsystem_name
57
+ # when 'sftp'
58
+ # pid = spawn("/path/to/hrr_rb_sftp_server.rb", {in: ctx.io[0], out: ctx.io[1], err: ctx.io[2]})
59
+ # exitstatus = Process.waitpid(pid).to_i
60
+ # else
61
+ # # Do something for other subsystem, or just return exitstatus
62
+ # exitstatus = 0
63
+ # end
64
+ # exitstatus
65
+ # }
66
+ # }
67
+ # options['connection_channel_request_subsystem'] = subsys
68
+ #
69
+ # @example hrr_rb_sftp_server.rb
70
+ # #!/usr/bin/env ruby
71
+ # require "hrr_rb_sftp"
72
+ # server = HrrRbSftp::Server.new(logger: nil)
73
+ # server.start($stdin, $stdout, $stderr)
74
+ #
75
+ # @example Replacing OpenSSH's sftp-server
76
+ # $ cat /etc/ssh/sshd_config | grep Subsystem
77
+ # #Subsystem sftp /usr/lib/openssh/sftp-server # Comment out the original line
78
+ # Subsystem sftp /path/to/hrr_rb_sftp_server.rb
79
+ #
1
80
  module HrrRbSftp
2
81
  end
3
82
 
4
- require "fileutils"
5
83
  require "stringio"
6
84
  require "etc"
7
85
 
@@ -1,31 +1,65 @@
1
1
  module HrrRbSftp
2
+
3
+ #
4
+ # This module is used to log message with useful logging key.
5
+ #
6
+ # @example
7
+ # class SomeClass
8
+ # include HrrRbSftp::Loggable
9
+ # def initialize logger
10
+ # self.logger = logger
11
+ # end
12
+ # def log_some_info
13
+ # log_info { "something" }
14
+ # end
15
+ # end
16
+ #
2
17
  module Loggable
18
+
19
+ #
20
+ # A logger instance that has #fatal, #error, #warn, #info, and #debug methods.
21
+ #
3
22
  attr_accessor :logger
4
23
 
24
+ #
25
+ # Outputs fatal message when the logger's log level fatal or higher.
26
+ #
5
27
  def log_fatal
6
28
  if logger
7
29
  logger.fatal(log_key){ yield }
8
30
  end
9
31
  end
10
32
 
33
+ #
34
+ # Outputs error message when the logger's log level error or higher.
35
+ #
11
36
  def log_error
12
37
  if logger
13
38
  logger.error(log_key){ yield }
14
39
  end
15
40
  end
16
41
 
42
+ #
43
+ # Outputs warn message when the logger's log level warn or higher.
44
+ #
17
45
  def log_warn
18
46
  if logger
19
47
  logger.warn(log_key){ yield }
20
48
  end
21
49
  end
22
50
 
51
+ #
52
+ # Outputs info message when the logger's log level info or higher.
53
+ #
23
54
  def log_info
24
55
  if logger
25
56
  logger.info(log_key){ yield }
26
57
  end
27
58
  end
28
59
 
60
+ #
61
+ # Outputs debug message when the logger's log level debug or higher.
62
+ #
29
63
  def log_debug
30
64
  if logger
31
65
  logger.debug(log_key){ yield }
@@ -1,56 +1,62 @@
1
1
  module HrrRbSftp
2
+
3
+ #
4
+ # This class implements SFTP protocol operations.
5
+ #
2
6
  class Protocol
3
7
  include Loggable
4
8
 
9
+ #
10
+ # @return [Array] A list of SFTP protocol versions that the library supports.
11
+ #
5
12
  def self.versions
6
13
  constants.select{|c| c.to_s.start_with?("Version")}.map{|c| const_get(c)}.map{|klass| klass::PROTOCOL_VERSION}
7
14
  end
8
15
 
16
+ #
17
+ # @return [Array] A list of extension-pair that the library supports.
18
+ #
19
+ def self.extension_pairs version
20
+ version_class = const_get(:"Version#{version}")
21
+ if version_class.const_defined?(:Extensions)
22
+ version_class::Extensions.extension_pairs
23
+ else
24
+ []
25
+ end
26
+ end
27
+
28
+ #
29
+ # @param version [Integer] Protocol version.
30
+ # @param logger [Logger] Logger.
31
+ #
9
32
  def initialize version, logger: nil
10
33
  self.logger = logger
11
34
 
12
- @handles = Hash.new
13
- @version = version
14
- @version_class = self.class.const_get(:"Version#{@version}")
15
- packet_classes = @version_class::Packet.constants.select{|c| c.to_s.start_with?("SSH_FXP_")}.map{|c| @version_class::Packet.const_get(c)}
16
- @packets = packet_classes.map{|pkt| [pkt::TYPE, pkt.new(@handles, logger: logger)]}.inject(Hash.new){|h,(k,v)| h.update({k => v})}
35
+ @context = Hash.new
36
+ @context[:version] = version
37
+ @context[:handles] = Hash.new
38
+ @packets = self.class.const_get(:"Version#{version}")::Packets.new(@context, logger: logger)
17
39
  end
18
40
 
41
+ #
42
+ # Responds to a request.
43
+ #
44
+ # @param request_payload [String] Request payload.
45
+ # @return [String] Response payload that is encoded packet generated by each SFTP protocol version and each request responder.
46
+ #
19
47
  def respond_to request_payload
20
- request_type = request_payload[0].unpack("C")[0]
21
- response_packet = if @packets.has_key?(request_type)
22
- begin
23
- request_packet = @packets[request_type].decode request_payload
24
- rescue => e
25
- {
26
- :"type" => @version_class::Packet::SSH_FXP_STATUS::TYPE,
27
- :"request-id" => (request_payload[1,4].unpack("N")[0] || 0),
28
- :"code" => @version_class::Packet::SSH_FXP_STATUS::SSH_FX_BAD_MESSAGE,
29
- :"error message" => e.message,
30
- :"language tag" => "",
31
- }
32
- else
33
- @packets[request_type].respond_to request_packet
34
- end
35
- else
36
- {
37
- :"type" => @version_class::Packet::SSH_FXP_STATUS::TYPE,
38
- :"request-id" => (request_payload[1,4].unpack("N")[0] || 0),
39
- :"code" => @version_class::Packet::SSH_FXP_STATUS::SSH_FX_OP_UNSUPPORTED,
40
- :"error message" => "Unsupported type: #{request_type}",
41
- :"language tag" => "",
42
- }
43
- end
44
- response_type = response_packet[:"type"]
45
- @packets[response_type].encode response_packet
48
+ @packets.respond_to request_payload
46
49
  end
47
50
 
51
+ #
52
+ # Closes opened and not closed handles.
53
+ #
48
54
  def close_handles
49
55
  log_info { "closing handles" }
50
- @handles.each do |k, v|
56
+ @context[:handles].each do |k, v|
51
57
  v.close rescue nil
52
58
  end
53
- @handles.clear
59
+ @context[:handles].clear
54
60
  log_info { "handles closed" }
55
61
  end
56
62
  end
@@ -1,10 +1,13 @@
1
1
  module HrrRbSftp
2
2
  class Protocol
3
+
4
+ #
5
+ # This module implements SFTP protocol version independent common functions.
6
+ #
3
7
  module Common
4
8
  end
5
9
  end
6
10
  end
7
11
 
8
- require "hrr_rb_sftp/protocol/common/data_type"
9
- require "hrr_rb_sftp/protocol/common/packetable"
10
- require "hrr_rb_sftp/protocol/common/packet"
12
+ require "hrr_rb_sftp/protocol/common/data_types"
13
+ require "hrr_rb_sftp/protocol/common/packets"
@@ -0,0 +1,19 @@
1
+ module HrrRbSftp
2
+ class Protocol
3
+ module Common
4
+
5
+ #
6
+ # This module implements SFTP protocol version common data types to be used to encode or decode packet.
7
+ #
8
+ module DataTypes
9
+ end
10
+ end
11
+ end
12
+ end
13
+
14
+ require "hrr_rb_sftp/protocol/common/data_types/byte"
15
+ require "hrr_rb_sftp/protocol/common/data_types/uint32"
16
+ require "hrr_rb_sftp/protocol/common/data_types/uint64"
17
+ require 'hrr_rb_sftp/protocol/common/data_types/string'
18
+ require 'hrr_rb_sftp/protocol/common/data_types/extension_pair'
19
+ require 'hrr_rb_sftp/protocol/common/data_types/extension_pairs'
@@ -0,0 +1,40 @@
1
+ module HrrRbSftp
2
+ class Protocol
3
+ module Common
4
+ module DataTypes
5
+
6
+ #
7
+ # This module provides methods to convert ::Integer value and 8-bit unsigned binary string each other.
8
+ #
9
+ module Byte
10
+
11
+ #
12
+ # Convert ::Integer value into 8-bit unsigned binary string.
13
+ #
14
+ # @param arg [::Integer] ::Integer value to be converted.
15
+ # @raise [::ArgumentError] When arg is not between 0x00 and 0xff.
16
+ # @return [::String] Converted 8-bit unsigned binary string.
17
+ #
18
+ def self.encode arg
19
+ case arg
20
+ when 0x00..0xff
21
+ [arg].pack("C")
22
+ else
23
+ raise ArgumentError, "must be in #{0x00}..#{0xff}, but got #{arg.inspect}"
24
+ end
25
+ end
26
+
27
+ #
28
+ # Convert 8-bit unsigned binary into ::Integer value.
29
+ #
30
+ # @param io [::IO] ::IO instance that has buffer to be read.
31
+ # @return [::Integer] Converted ::Integer value.
32
+ #
33
+ def self.decode io
34
+ io.read(1).unpack("C")[0]
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,41 @@
1
+ module HrrRbSftp
2
+ class Protocol
3
+ module Common
4
+ module DataTypes
5
+
6
+ #
7
+ # This module provides methods to convert extension-name and extension-data pair represented in ::Hash and binary string each other.
8
+ #
9
+ module ExtensionPair
10
+
11
+ #
12
+ # Convert extension-name and extension-data pair represented in ::Hash into binary string.
13
+ #
14
+ # @param arg [::Hash{::Symbol=>::String}] Extension-name and extension-data pair represented in ::Hash to be converted.
15
+ # @raise [::ArgumentError] When arg is not ::Hash value.
16
+ # @return [::String] Converted binary string.
17
+ #
18
+ def self.encode arg
19
+ unless arg.kind_of? ::Hash
20
+ raise ArgumentError, "must be a kind of Hash, but got #{arg.inspect}"
21
+ end
22
+ DataTypes::String.encode(arg[:"extension-name"]) + DataTypes::String.encode(arg[:"extension-data"])
23
+ end
24
+
25
+ #
26
+ # Convert binary string into extension-name and extension-data pair represented in ::Hash.
27
+ #
28
+ # @param io [::IO] ::IO instance that has buffer to be read.
29
+ # @return [::Hash{::Symbol=>::String}] Converted extension-name and extension-data pair represented in ::Hash.
30
+ #
31
+ def self.decode io
32
+ {
33
+ :"extension-name" => DataTypes::String.decode(io),
34
+ :"extension-data" => DataTypes::String.decode(io),
35
+ }
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,42 @@
1
+ module HrrRbSftp
2
+ class Protocol
3
+ module Common
4
+ module DataTypes
5
+
6
+ #
7
+ # This module provides methods to convert list of extension-name and extension-data pair represented in ::Array and binary string each other.
8
+ #
9
+ module ExtensionPairs
10
+
11
+ #
12
+ # Convert list of extension-name and extension-data pair represented in ::Array into binary string.
13
+ #
14
+ # @param arg [::Array<::Hash{::Symbol=>::String}>] List of extension-name and extension-data pair represented in ::Array to be converted.
15
+ # @raise [::ArgumentError] When arg is not ::Array value.
16
+ # @return [::String] Converted binary string.
17
+ #
18
+ def self.encode arg
19
+ unless arg.kind_of? ::Array
20
+ raise ArgumentError, "must be a kind of Array, but got #{arg.inspect}"
21
+ end
22
+ arg.map{|arg| ExtensionPair.encode(arg)}.join
23
+ end
24
+
25
+ #
26
+ # Convert binary string into list of extension-name and extension-data pair represented in ::Array.
27
+ #
28
+ # @param io [::IO] ::IO instance that has buffer to be read.
29
+ # @return [::Array<::Hash{::Symbol=>::String}>] Converted list of extension-name and extension-data pair represented in ::Array.
30
+ #
31
+ def self.decode io
32
+ extension_pairs = Array.new
33
+ until io.eof?
34
+ extension_pairs.push ExtensionPair.decode(io)
35
+ end
36
+ extension_pairs
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end