kong--kong
226 行
5.5 KiB
Lua
226 行
5.5 KiB
Lua
local cjson = require "cjson"
|
|
local shallow_copy = require("kong.tools.table").shallow_copy
|
|
|
|
|
|
local setmetatable = setmetatable
|
|
local tostring = tostring
|
|
local ipairs = ipairs
|
|
local table = table
|
|
local type = type
|
|
|
|
|
|
-- Get an array of SNI names from either
|
|
-- an array(sort) or ngx.null(return {})
|
|
-- Returns an error if the list has duplicates
|
|
-- Returns nil if input is falsy.
|
|
local function parse_name_list(input, errors)
|
|
local name_list
|
|
if type(input) == "table" then
|
|
name_list = shallow_copy(input)
|
|
|
|
elseif input == ngx.null then
|
|
name_list = {}
|
|
|
|
else
|
|
return nil
|
|
end
|
|
|
|
local found = {}
|
|
for _, name in ipairs(name_list) do
|
|
if found[name] then
|
|
local err_t = errors:schema_violation({
|
|
snis = name .. " is duplicated",
|
|
})
|
|
return nil, tostring(err_t), err_t
|
|
end
|
|
found[name] = true
|
|
end
|
|
|
|
table.sort(name_list)
|
|
return setmetatable(name_list, cjson.array_mt)
|
|
end
|
|
|
|
|
|
local _Certificates = {}
|
|
|
|
-- Creates a certificate
|
|
-- If the provided cert has a field called "snis" it will be used to generate server
|
|
-- names associated to the cert, after being parsed by parse_name_list.
|
|
-- Returns a certificate with the snis sorted alphabetically.
|
|
function _Certificates:insert(cert, options)
|
|
local name_list, err, err_t = parse_name_list(cert.snis, self.errors)
|
|
if err then
|
|
return nil, err, err_t
|
|
end
|
|
|
|
if name_list then
|
|
local ok, err, err_t = self.db.snis:check_list_is_new(name_list)
|
|
if not ok then
|
|
return nil, err, err_t
|
|
end
|
|
end
|
|
|
|
cert, err, err_t = self.super.insert(self, cert, options)
|
|
if not cert then
|
|
return nil, err, err_t
|
|
end
|
|
|
|
cert.snis = name_list or cjson.empty_array
|
|
|
|
if name_list then
|
|
local ok, err, err_t = self.db.snis:insert_list(cert, name_list, options)
|
|
if not ok then
|
|
return nil, err, err_t
|
|
end
|
|
end
|
|
|
|
return cert
|
|
end
|
|
|
|
-- Update override
|
|
-- If the cert has a "snis" attribute it will be used to update the SNIs
|
|
-- associated to the cert.
|
|
-- * If the cert had any names associated which are not on `snis`, they will be
|
|
-- removed.
|
|
-- * Any new certificates will be added to the db.
|
|
-- Returns an error if any of the new certificates where already assigned to a cert different
|
|
-- from the one identified by cert_pk
|
|
function _Certificates:update(cert_pk, cert, options)
|
|
local name_list, err, err_t = parse_name_list(cert.snis, self.errors)
|
|
if err then
|
|
return nil, err, err_t
|
|
end
|
|
|
|
if name_list then
|
|
local ok, err, err_t = self.db.snis:check_list_is_new(name_list, cert_pk.id)
|
|
if not ok then
|
|
return nil, err, err_t
|
|
end
|
|
end
|
|
|
|
cert, err, err_t = self.super.update(self, cert_pk, cert, options)
|
|
if err then
|
|
return nil, err, err_t
|
|
end
|
|
|
|
if name_list then
|
|
cert.snis = name_list
|
|
|
|
local ok, err, err_t = self.db.snis:update_list(cert_pk, name_list)
|
|
if not ok then
|
|
return nil, err, err_t
|
|
end
|
|
|
|
else
|
|
cert.snis, err, err_t = self.db.snis:list_for_certificate(cert_pk)
|
|
if not cert.snis then
|
|
return nil, err, err_t
|
|
end
|
|
end
|
|
|
|
return cert
|
|
end
|
|
|
|
-- Upsert override
|
|
function _Certificates:upsert(cert_pk, cert, options)
|
|
local name_list, err, err_t = parse_name_list(cert.snis, self.errors)
|
|
if err then
|
|
return nil, err, err_t
|
|
end
|
|
|
|
if name_list then
|
|
local ok, err, err_t = self.db.snis:check_list_is_new(name_list, cert_pk.id)
|
|
if not ok then
|
|
return nil, err, err_t
|
|
end
|
|
end
|
|
|
|
cert, err, err_t = self.super.upsert(self, cert_pk, cert, options)
|
|
if err then
|
|
return nil, err, err_t
|
|
end
|
|
|
|
if name_list then
|
|
cert.snis = name_list
|
|
|
|
local ok, err, err_t = self.db.snis:update_list(cert_pk, name_list)
|
|
if not ok then
|
|
return nil, err, err_t
|
|
end
|
|
|
|
else
|
|
cert.snis, err, err_t = self.db.snis:list_for_certificate(cert_pk)
|
|
if not cert.snis then
|
|
return nil, err, err_t
|
|
end
|
|
end
|
|
|
|
return cert
|
|
end
|
|
|
|
|
|
-- Returns the certificate identified by cert_pk but adds the
|
|
-- `snis` pseudo attribute to it. It is an array of strings
|
|
-- representing the SNIs associated to the certificate.
|
|
function _Certificates:select_with_name_list(cert_pk, options)
|
|
local cert, err, err_t = self:select(cert_pk, options)
|
|
if err_t then
|
|
return nil, err, err_t
|
|
end
|
|
|
|
if not cert then
|
|
local err_t = self.errors:not_found(cert_pk)
|
|
return nil, tostring(err_t), err_t
|
|
end
|
|
|
|
cert.snis, err, err_t = self.db.snis:list_for_certificate(cert_pk)
|
|
if err_t then
|
|
return nil, err, err_t
|
|
end
|
|
|
|
return cert
|
|
end
|
|
|
|
-- Returns a page of certificates, each with the `snis` pseudo-attribute
|
|
-- associated to them. This method does N+1 queries, but for now we are limited
|
|
-- by the DAO's select options (we can't query for "all the SNIs for this
|
|
-- list of certificate ids" in one go).
|
|
function _Certificates:page(size, offset, options)
|
|
local certs, err, err_t, offset = self.super.page(self, size, offset, options)
|
|
if not certs then
|
|
return nil, err, err_t
|
|
end
|
|
|
|
for i=1, #certs do
|
|
local cert = certs[i]
|
|
local snis, err, err_t = self.db.snis:list_for_certificate(cert)
|
|
if not snis then
|
|
return nil, err, err_t
|
|
end
|
|
|
|
cert.snis = snis
|
|
end
|
|
|
|
return certs, nil, nil, offset
|
|
end
|
|
|
|
-- Overrides the default delete function by cascading-deleting all the SNIs
|
|
-- associated to the certificate
|
|
function _Certificates:delete(cert_pk, options)
|
|
local name_list, err, err_t =
|
|
self.db.snis:list_for_certificate(cert_pk)
|
|
if not name_list then
|
|
return nil, err, err_t
|
|
end
|
|
|
|
local ok, err, err_t = self.db.snis:delete_list(name_list)
|
|
if not ok then
|
|
return nil, err, err_t
|
|
end
|
|
|
|
return self.super.delete(self, cert_pk, options)
|
|
end
|
|
|
|
|
|
return _Certificates
|