diff --git a/raven.lua b/raven.lua index 823933c..c8a32e3 100644 --- a/raven.lua +++ b/raven.lua @@ -43,12 +43,17 @@ local table_insert = table.insert local debug = false local socket +local ssl local catcher_trace_level = 4 if not ngx then local ok, luasocket = pcall(require, "socket") if not ok then error("No socket library found, you need ngx.socket or luasocket.") end + local ok, luassl = pcall(require, "ssl") + if ok then + ssl = luassl + end socket = luasocket else socket = ngx.socket @@ -161,7 +166,7 @@ local function _parse_host_port(protocol, host) local i = string_find(host, ":") if not i then -- TODO - return host, 80 + return host, nil end local port_str = string_sub(host, i + 1) @@ -193,7 +198,7 @@ local function _parse_dsn(dsn, obj) local host, port, err = _parse_host_port(obj.protocol, obj.long_host) - if not host or not port then + if not host then return nil, err end @@ -388,8 +393,10 @@ function _M.send_report(self, json, conf) local json_str = json_encode(json) local ok, err - if self.protocol == "http" then - ok, err = self:http_send(json_str) + if self.protocol == "https" then + ok, err = self:http_send(json_str, true) + elseif self.protocol == "http" then + ok, err = self:http_send(json_str, false) else error("protocol not implemented yet: " .. self.protocol) end @@ -521,23 +528,84 @@ function _M.http_send_core(self, json_str) return string_sub(res, s2 + 1) end +-- lua_wrap_tls: Enables TLS for luasocket. Requires luasec. +function _M.lua_wrap_tls(self, sock) + if not ssl then + error("no ssl library found, please install luasec") + end + + local ok, err + + sock, err = ssl.wrap(sock, { + mode = "client", + protocol = "tlsv1", + verify = "peer", + options = "all", + }) + if not sock then + return nil, err + end + + ok, err = sock:dohandshake() + if not ok then + return nil, err + end + + return sock +end + +-- ngx_wrap_tls: Enables TLS for ngx.socket +function _M.ngx_wrap_tls(self, sock) + local session, err = sock:sslhandshake(false, self.host, true) + if not session then + return nil, err + end + return sock +end + +-- wrap_tls: Wraps a connected socket with TLS +function _M.wrap_tls(self, sock) + if ngx then + return self:ngx_wrap_tls(sock) + end + return self:lua_wrap_tls(sock) +end + -- http_send: actually sends the structured data to the Sentry server using --- HTTP -function _M.http_send(self, json_str) +-- HTTP or HTTPS +function _M.http_send(self, json_str, secure) local ok, err local sock + local port = self.port sock, err = socket.tcp() if not sock then return nil, err end - self.sock = sock - ok, err = sock:connect(self.host, self.port) + -- Rely on default port values for http and https + if not port then + port = secure and 443 or 80 + end + + ok, err = sock:connect(self.host, port) if not ok then return nil, err end + if secure then + -- Sprinkle on some TLS juice + local tlssock, err = self:wrap_tls(sock) + if not tlssock then + -- Need to close the tcp connection yet before bailing + sock:close() + return nil, err + end + sock = tlssock + end + + self.sock = sock + ok, err = self:http_send_core(json_str) sock:close() diff --git a/tests/test_sanity.lua b/tests/test_sanity.lua index 0503c58..112529d 100644 --- a/tests/test_sanity.lua +++ b/tests/test_sanity.lua @@ -14,7 +14,7 @@ function test_parse_dsn() assert_equal("public", obj.public_key) assert_equal("secret", obj.secret_key) assert_equal("example.com", obj.host) - assert_equal(80, obj.port) + assert_equal(nil, obj.port) assert_equal("/sentry/", obj.path) assert_equal("project-id", obj.project_id) assert_equal("/sentry/api/project-id/store/", obj.request_uri) @@ -64,7 +64,7 @@ end function test_parse_host_port1() local host, port = raven._parse_host_port("http", "somehost.com") assert_equal("somehost.com", host) - assert_equal(80, port) + assert_equal(nil, port) end function test_parse_host_port2()