diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..643f1f1 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,44 @@ +name: Lint + +on: + pull_request: {} + workflow_dispatch: {} + push: + branches: + - main + - kong-dev + - master + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + lua-check: + name: Lua Check + runs-on: ubuntu-latest + permissions: + contents: read + issues: read + checks: write + pull-requests: write + if: (github.actor != 'dependabot[bot]') + + steps: + - name: Checkout source code + uses: actions/checkout@v3 + + # Optional step to run on only changed files + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@4edd678ac3f81e2dc578756871e4d00c19191daf + with: + files: | + **.lua + + - name: Lua Check + if: steps.changed-files.outputs.any_changed == 'true' + uses: Kong/public-shared-actions/code-check-actions/lua-lint@33449c46c6766a3d3c8f167cc383381225862b36 + with: + additional_args: '--no-default-config' + files: ${{ steps.changed-files.outputs.all_changed_files }} diff --git a/.github/workflows/sast.yml b/.github/workflows/sast.yml new file mode 100644 index 0000000..072bfe8 --- /dev/null +++ b/.github/workflows/sast.yml @@ -0,0 +1,28 @@ +name: SAST + +on: + pull_request: {} + push: + branches: + - master + - main + - kong-dev + workflow_dispatch: {} + + +jobs: + semgrep: + name: Semgrep SAST + runs-on: ubuntu-latest + permissions: + # required for all workflows + security-events: write + # only required for workflows in private repositories + actions: read + contents: read + + if: (github.actor != 'dependabot[bot]') + + steps: + - uses: actions/checkout@v3 + - uses: Kong/public-shared-actions/security-actions/semgrep@33449c46c6766a3d3c8f167cc383381225862b36 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ec2887f..3d9a0b9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,11 +20,11 @@ jobs: steps: - uses: actions/checkout@master - - uses: leafo/gh-actions-lua@master + - uses: leafo/gh-actions-lua@ef9239997afff6d2d8b42ec9729c1d4b7f2f1302 with: luaVersion: ${{ matrix.luaVersion }} - - uses: leafo/gh-actions-luarocks@master + - uses: leafo/gh-actions-luarocks@e65774a6386cb4f24e293dca7fc4ff89165b64c5 - name: dependencies run: | @@ -64,11 +64,11 @@ jobs: steps: - uses: actions/checkout@master - - uses: leafo/gh-actions-openresty@main + - uses: leafo/gh-actions-openresty@4bd905d98dcbee29a2d95771d0b1e743e890fdfa with: openrestyVersion: "1.19.9.1" - - uses: leafo/gh-actions-luarocks@master + - uses: leafo/gh-actions-luarocks@e65774a6386cb4f24e293dca7fc4ff89165b64c5 with: withLuaPath: "/usr/local/openresty/luajit/" diff --git a/README.md b/README.md index e3db5c0..1ca8c70 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,12 @@ of the [cosocket api](https://github.com/openresty/lua-nginx-module#ngxsockettcp) to provide asynchronous queries but it also works in the regular any Lua environment where -[LuaSocket][] or [cqueues][] is available. +[LuaSocket][] or [cqueues][] is available. pgmoon optionally requires: + +- [LuaCrypto][2] for authentication with MD5 +- [LuaSec][6] for SSL connections + +For authentication with SCRAM-SHA-256 (without channel binding support) pgmoon requires [luaossl](https://luarocks.org/modules/daurnimator/luaossl) only. For authentication with SCRAM-SHA-256-PLUS (with channel binding support) it requires [LuaSec][6] for the socket type `luasocket` and [lua-resty-openssl](https://luarocks.org/modules/fffonion/lua-resty-openssl) for the socket type `nginx`. It's a perfect candidate for running your queries both inside OpenResty's environment and on the command line (eg. tests) in web frameworks like [Lapis][]. diff --git a/pgmoon-dev-1.rockspec b/kong-pgmoon-2.3.2.0-1.rockspec similarity index 77% rename from pgmoon-dev-1.rockspec rename to kong-pgmoon-2.3.2.0-1.rockspec index fa02a4d..e80681f 100644 --- a/pgmoon-dev-1.rockspec +++ b/kong-pgmoon-2.3.2.0-1.rockspec @@ -1,15 +1,16 @@ -package = "pgmoon" -version = "dev-1" +package = "kong-pgmoon" +version = "2.3.2.0-1" source = { - url = "git+https://github.com/leafo/pgmoon.git" + url = "git+https://github.com/Kong/pgmoon.git", + tag = "2.3.2.0" -- internal kong version adds an extra digit to the version } description = { summary = "Postgres driver for OpenResty and Lua", detailed = [[PostgreSQL driver written in pure Lua for use with OpenResty's cosocket API. Can also be used in regular Lua with LuaSocket and LuaCrypto.]], - homepage = "https://github.com/leafo/pgmoon", - maintainer = "Leaf Corcoran ", + homepage = "https://github.com/Kong/pgmoon", + maintainer = "Kong Inc", license = "MIT" } diff --git a/pgmoon/init.lua b/pgmoon/init.lua index 9b902c8..b1f973d 100644 --- a/pgmoon/init.lua +++ b/pgmoon/init.lua @@ -6,9 +6,15 @@ do local _obj_0 = require("pgmoon.bit") rshift, lshift, band, bxor = _obj_0.rshift, _obj_0.lshift, _obj_0.band, _obj_0.bxor end +local pl_file +local ssl +if ngx then + pl_file = require("pl.file") + ssl = require("ngx.ssl") +end local unpack = table.unpack or unpack local DEBUG = false -local VERSION = "1.15.0" +local VERSION = "2.3.2.0" local _len _len = function(thing, t) if t == nil then @@ -288,7 +294,7 @@ do end, create_cqueues_openssl_context = function(self) if not (self.config.ssl_verify ~= nil or self.config.cert or self.config.key or self.config.ssl_version) then - return + return end local ssl_context = require("openssl.ssl.context") local out = ssl_context.new(self.config.ssl_version) @@ -307,12 +313,20 @@ do return out end, create_luasec_opts = function(self) + local key = self.config.key + local cert = self.config.cert + if self.sock_type == "nginx" and key and cert then + key = assert(ssl.parse_pem_priv_key(pl_file.read(key, true))) + cert = assert(ssl.parse_pem_cert(pl_file.read(cert, true))) + end return { - key = self.config.key, - certificate = self.config.cert, + key = key, + certificate = cert, cafile = self.config.cafile, protocol = self.config.ssl_version, - verify = self.config.ssl_verify and "peer" or "none" + verify = self.config.ssl_verify and "peer" or "none", + ssl_version = self.config.ssl_version or "any", + options = { "all", "no_sslv2", "no_sslv3", "no_tlsv1" } } end, auth = function(self) @@ -401,9 +415,13 @@ do local server_cert = self.sock:getpeercertificate() pem, signature = server_cert:pem(), server_cert:getsignaturename() end - signature = signature:lower() - if signature:match("^md5") or signature:match("^sha1") then + if signature:match("^md5") or signature:match("^sha1") or signature:match("sha1$") or signature:match("sha256$") then signature = "sha256" + else + local objects = require("resty.openssl.objects") + local sigid = assert(objects.txt2nid(signature)) + local digest_nid = assert(objects.find_sigid_algs(sigid)) + signature = assert(objects.nid2table(digest_nid).sn) end cbind_data = assert(x509_digest(pem, signature)) end @@ -936,7 +954,26 @@ do if t == MSG_TYPE_B.parameter_status then local _exp_0 = self.sock_type if "nginx" == _exp_0 then - return self.sock:sslhandshake(false, nil, self.config.ssl_verify) + local luasec_opts = self.config.luasec_opts or self:create_luasec_opts() + + -- version compability check to see if setclientcert is supported + if self.sock.setclientcert then + local ok, err_internal = self.sock:setclientcert(luasec_opts.certificate, luasec_opts.key) + if not ok then + return false, err_internal + end + return self.sock:sslhandshake(false, nil, self.config.ssl_verify) + else + if self.sock.tlshandshake then + return self.sock:tlshandshake({ + verify = self.config.ssl_verify, + client_cert = luasec_opts.certificate, + client_priv_key = luasec_opts.key + }) + else + return self.sock:sslhandshake(false, nil, self.config.ssl_verify) + end + end elseif "luasocket" == _exp_0 then return self.sock:sslhandshake(self.config.luasec_opts or self:create_luasec_opts()) elseif "cqueues" == _exp_0 then diff --git a/pgmoon/init.moon b/pgmoon/init.moon index 96e1a5b..9849545 100644 --- a/pgmoon/init.moon +++ b/pgmoon/init.moon @@ -3,13 +3,27 @@ import insert from table import rshift, lshift, band, bxor from require "pgmoon.bit" +local pl_file +local ssl + +if ngx + pl_file = require "pl.file" + ssl = require "ngx.ssl" + +local pl_file +local ssl + +if ngx + pl_file = require "pl.file" + ssl = require "ngx.ssl" + unpack = table.unpack or unpack -- Protocol documentation: -- https://www.postgresql.org/docs/current/protocol-message-formats.html DEBUG = false -VERSION = "1.15.0" +VERSION = "2.3.2.0" _len = (thing, t=type(thing)) -> switch t @@ -306,12 +320,20 @@ class Postgres out create_luasec_opts: => + key = @config.key + cert = @config.cert + + if @sock_type == "nginx" and key and cert + key = assert(ssl.parse_pem_priv_key(pl_file.read(key, true))) + cert = assert(ssl.parse_pem_cert(pl_file.read(cert, true))) { - key: @config.key - certificate: @config.cert + key: key + certificate: cert cafile: @config.cafile protocol: @config.ssl_version - verify: @config.ssl_verify and "peer" or "none" + verify: @config.ssl_verify and "peer" or "none", + ssl_version: @config.ssl_version or "any" + options: { "all", "no_sslv2", "no_sslv3", "no_tlsv1" } } @@ -912,7 +934,19 @@ class Postgres if t == MSG_TYPE_B.parameter_status switch @sock_type when "nginx" - @sock\sslhandshake false, nil, @config.ssl_verify + luasec_opts = @config.luasec_opts or @create_luasec_opts! + + -- version compability check to see if setclientcert is supported + if @sock.setclientcert + ok, err_internal = @sock\setclientcert luasec_opts.certificate, luasec_opts.key + if not ok + return false, err_internal + return @sock\sslhandshake false, nil, @config.ssl_verify + else + if @sock.tlshandshake + return @sock\tlshandshake { verify: @config.ssl_verify, client_cert: luasec_opts.certificate, client_priv_key: luasec_opts.key } + else + return @sock\sslhandshake false, nil, @config.ssl_verify when "luasocket" @sock\sslhandshake @config.luasec_opts or @create_luasec_opts! when "cqueues"