hrr_rb_sftp 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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