diff --git a/changelog.d/94.change.txt b/changelog.d/94.change.txt new file mode 100644 index 0000000..981fc08 --- /dev/null +++ b/changelog.d/94.change.txt @@ -0,0 +1 @@ +Opening an `scp://` URI through `uri/open-scp` now percent-decodes the user, password and path (once, keeping a literal `+`) and passes an IPv6 address to SSH without its brackets, so `scp://user@[::1]/a%20b` downloads `/a b` from `::1`. Thanks @OskarEichler [#94] diff --git a/lib/uri/open-scp.rb b/lib/uri/open-scp.rb index 9fa4c4a..1ba0acd 100644 --- a/lib/uri/open-scp.rb +++ b/lib/uri/open-scp.rb @@ -10,10 +10,10 @@ class SCP def buffer_open(buf, proxy, open_options) options = open_options.dup options[:ssh] = { :port => port } - options[:ssh][:password] = password if password + options[:ssh][:password] = URI::DEFAULT_PARSER.unescape(password) if password options[:ssh].merge!(open_options[:ssh] || {}) progress = options.delete(:progress_proc) - buf << Net::SCP.download!(host, user, path, nil, options, &progress) + buf << Net::SCP.download!(hostname, user && URI::DEFAULT_PARSER.unescape(user), URI::DEFAULT_PARSER.unescape(path), nil, options, &progress) buf.io.rewind end diff --git a/test/test_open_scp.rb b/test/test_open_scp.rb index e908909..57284ee 100644 --- a/test/test_open_scp.rb +++ b/test/test_open_scp.rb @@ -35,6 +35,20 @@ def stub_scp(*chunks) fake end + def test_ipv6_host_is_passed_without_brackets + stub_scp("data") + URI("scp://user@[::1]:2222/path").open(&:read) + assert_equal ["::1", "user"], @start_args.first(2) + end + + def test_user_password_and_path_are_percent_decoded_once + fake = stub_scp("data") + URI("scp://us%65r%2Bx:p%40ss%3Aw+rd@example.com/dir%2Fsub/a%20b+c%2541%C3%A9").open(&:read) + assert_equal ["example.com", "user+x", { port: 22, password: "p@ss:w+rd" }], @start_args + assert_equal "/dir/sub/a b+c%41é", fake.remote + assert_equal Encoding::UTF_8, fake.remote.encoding + end + def test_uri_port_and_password_are_passed_to_ssh stub_scp("data") assert_equal "data", URI("scp://user:secret@example.com:2222/file").open(&:read)