Skip to content

Commit

Permalink
feat(api) restrict data manipulation operations on 'off' db with errors
Browse files Browse the repository at this point in the history
  • Loading branch information
bungle committed Feb 13, 2019
1 parent ac8a1ce commit 1bd6ff5
Show file tree
Hide file tree
Showing 6 changed files with 347 additions and 4 deletions.
8 changes: 6 additions & 2 deletions kong/api/endpoints.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ local ERRORS_HTTP_CODES = {
[Errors.codes.INVALID_SIZE] = 400,
[Errors.codes.INVALID_UNIQUE] = 400,
[Errors.codes.INVALID_OPTIONS] = 400,
[Errors.codes.OPERATION_UNSUPPORTED] = 405,
}


Expand Down Expand Up @@ -111,8 +112,11 @@ local function handle_error(err_t)
return app_helpers.yield_error(err_t)
end

local body = utils.get_default_exit_body(status, err_t)
return kong.response.exit(status, body)
if err_t.code == Errors.codes.OPERATION_UNSUPPORTED then
return kong.response.exit(status, err_t)
end

return kong.response.exit(status, utils.get_default_exit_body(status, err_t))
end


Expand Down
5 changes: 5 additions & 0 deletions kong/api/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ local function new_db_on_error(self)
return kong.response.exit(404, err)
end

if err.code == Errors.codes.OPERATION_UNSUPPORTED then
kong.log.err(err)
return kong.response.exit(405, err)
end

if err.code == Errors.codes.PRIMARY_KEY_VIOLATION
or err.code == Errors.codes.UNIQUE_VIOLATION
then
Expand Down
11 changes: 11 additions & 0 deletions kong/db/errors.lua
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ local ERRORS = {
INVALID_SIZE = 9, -- page(size, offset) is invalid
INVALID_UNIQUE = 10, -- unique field value is invalid
INVALID_OPTIONS = 11, -- invalid options given
OPERATION_UNSUPPORTED = 12, -- operation is not supported with this strategy
}


Expand All @@ -55,6 +56,7 @@ local ERRORS_NAMES = {
[ERRORS.INVALID_SIZE] = "invalid size",
[ERRORS.INVALID_UNIQUE] = "invalid unique %s",
[ERRORS.INVALID_OPTIONS] = "invalid options",
[ERRORS.OPERATION_UNSUPPORTED] = "operation unsupported",
}


Expand Down Expand Up @@ -394,4 +396,13 @@ function _M:invalid_options(errors)
end


function _M:operation_unsupported(err)
if type(err) ~= "string" then
error("err must be a string", 2)
end

return new_err_t(self, ERRORS.OPERATION_UNSUPPORTED, err)
end


return _M
47 changes: 45 additions & 2 deletions kong/db/strategies/off/init.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
local declarative_config = require("kong.db.schema.others.declarative_config")


local kong = kong
local fmt = string.format
local tostring = tostring
local tonumber = tonumber
local encode_base64 = ngx.encode_base64
local decode_base64 = ngx.decode_base64

local off = {}


Expand All @@ -9,7 +16,22 @@ _mt.__index = _mt


local function page_for_key(self, key, size, offset)
offset = offset and tonumber(offset) or 1
if offset then
local token = decode_base64(offset)
if not token then
return nil, self.errors:invalid_offset(offset, "bad base64 encoding")
end

token = tonumber(token)
if not token then
return nil, self.errors:invalid_offset(offset, "invalid offset")
end

offset = token

else
offset = 1
end

if not kong.cache then
return {}
Expand Down Expand Up @@ -39,7 +61,7 @@ local function page_for_key(self, key, size, offset)
end

if offset then
return ret, nil, tostring(offset + size)
return ret, nil, encode_base64(tostring(offset + size), true)
end

return ret
Expand Down Expand Up @@ -77,13 +99,34 @@ end


function off.new(connector, schema, errors)
local unsupported = function(operation)
local err = fmt("cannot %s '%s' entities when not using a database", operation, schema.name)
return function()
return nil, errors:operation_unsupported(err)
end
end

local unsupported_by = function(operation)
local err = fmt("cannot %s '%s' entities by '%s' when not using a database", operation, schema.name, '%s')
return function(_, field_name)
return nil, errors:operation_unsupported(fmt(err, field_name))
end
end

local self = {
connector = connector, -- instance of kong.db.strategies.off.connector
schema = schema,
errors = errors,
page = page,
select = select,
select_by_field = select_by_field,
insert = unsupported("create"),
update = unsupported("update"),
upsert = unsupported("create or update"),
delete = unsupported("remove"),
update_by_field = unsupported_by("update"),
upsert_by_field = unsupported_by("create or update"),
delete_by_field = unsupported_by("remove"),
truncate = function() return true end,
}

Expand Down
98 changes: 98 additions & 0 deletions spec/02-integration/03-db/08-off_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
local Errors = require "kong.db.errors"
local helpers = require "spec.helpers"


describe("kong.db [#off]", function()
local db
lazy_setup(function()
local _
_, db = helpers.get_db_utils("off", { })
end)

describe("Routes", function()

describe(":insert()", function()
it("returns operation unsupported error", function()
local _, err_t = db.strategies.routes:insert()
assert.same({
code = Errors.codes.OPERATION_UNSUPPORTED,
name = Errors.names[Errors.codes.OPERATION_UNSUPPORTED],
message = "cannot create 'routes' entities when not using a database",
strategy = "off",
}, err_t)
end)
end)

describe(":update()", function()
it("returns operation unsupported error", function()
local _, err_t = db.strategies.routes:update()
assert.same({
code = Errors.codes.OPERATION_UNSUPPORTED,
name = Errors.names[Errors.codes.OPERATION_UNSUPPORTED],
message = "cannot update 'routes' entities when not using a database",
strategy = "off",
}, err_t)
end)
end)

describe(":update_by_field()", function()
it("returns operation unsupported error", function()
local _, err_t = db.strategies.routes:update_by_field("name")
assert.same({
code = Errors.codes.OPERATION_UNSUPPORTED,
name = Errors.names[Errors.codes.OPERATION_UNSUPPORTED],
message = "cannot update 'routes' entities by 'name' when not using a database",
strategy = "off",
}, err_t)
end)
end)

describe(":upsert()", function()
it("returns operation unsupported error", function()
local _, err_t = db.strategies.routes:upsert()
assert.same({
code = Errors.codes.OPERATION_UNSUPPORTED,
name = Errors.names[Errors.codes.OPERATION_UNSUPPORTED],
message = "cannot create or update 'routes' entities when not using a database",
strategy = "off",
}, err_t)
end)
end)

describe(":upsert_by_field()", function()
it("returns operation unsupported error", function()
local _, err_t = db.strategies.routes:upsert_by_field("name")
assert.same({
code = Errors.codes.OPERATION_UNSUPPORTED,
name = Errors.names[Errors.codes.OPERATION_UNSUPPORTED],
message = "cannot create or update 'routes' entities by 'name' when not using a database",
strategy = "off",
}, err_t)
end)
end)

describe(":delete()", function()
it("returns operation unsupported error", function()
local _, err_t = db.strategies.routes:delete()
assert.same({
code = Errors.codes.OPERATION_UNSUPPORTED,
name = Errors.names[Errors.codes.OPERATION_UNSUPPORTED],
message = "cannot remove 'routes' entities when not using a database",
strategy = "off",
}, err_t)
end)
end)

describe(":delete_by_field()", function()
it("returns operation unsupported error", function()
local _, err_t = db.strategies.routes:delete_by_field("name")
assert.same({
code = Errors.codes.OPERATION_UNSUPPORTED,
name = Errors.names[Errors.codes.OPERATION_UNSUPPORTED],
message = "cannot remove 'routes' entities by 'name' when not using a database",
strategy = "off",
}, err_t)
end)
end)
end)
end)
Loading

0 comments on commit 1bd6ff5

Please sign in to comment.