bunkerweb 1.4.0
This commit is contained in:
1
deps/src/lua-resty-session/.gitignore
vendored
Normal file
1
deps/src/lua-resty-session/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/.project
|
||||
2
deps/src/lua-resty-session/.luacheckrc
vendored
Normal file
2
deps/src/lua-resty-session/.luacheckrc
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
std = "ngx_lua"
|
||||
|
||||
437
deps/src/lua-resty-session/Changes.md
vendored
Normal file
437
deps/src/lua-resty-session/Changes.md
vendored
Normal file
@@ -0,0 +1,437 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to `lua-resty-session` will be documented in this file.
|
||||
|
||||
## [3.10] - 2022-01-14
|
||||
### Fixed
|
||||
- 3.9 introduced an issue where calling session:regenerate with flush=true,
|
||||
didn't really flush if the session strategy was `regenerate`.
|
||||
|
||||
|
||||
## [3.9] - 2022-01-14
|
||||
### Fixed
|
||||
- Fix #138 issue of chunked cookies are not expired when session shrinks,
|
||||
thanks @alexdowad.
|
||||
- Fix #134 where regenerate strategy destroyed previous session when calling
|
||||
`session:regenerate`, it should just `ttl` the old session.
|
||||
|
||||
### Added
|
||||
- AES GCM mode support was added to AES cipher.
|
||||
This is recommended, but for backward compatibility it was not set as default.
|
||||
It will be changed in 4.0 release.
|
||||
- Redis ACL authentication is now available.
|
||||
- Add `session_redis_username`
|
||||
- Add `session_redis_password`
|
||||
- Deprecate `session_redis_auth`; use `session_redis_password`
|
||||
|
||||
### Changed
|
||||
- Optimize Redis and Memcache storage adapters to not connect to database
|
||||
when not needed.
|
||||
|
||||
|
||||
## [3.8] - 2021-01-04
|
||||
### Added
|
||||
- Connection options are now passed to `redis cluster client` as well.
|
||||
|
||||
|
||||
## [3.7] - 2020-10-27
|
||||
### Fixed
|
||||
- Fix #107 where `session.start` could release a lock for a short period
|
||||
|
||||
### Added
|
||||
- Add `keep_lock` argument to `session.open`
|
||||
- Add pluggable compressors, and implement `none` and `zlib` compressor
|
||||
|
||||
|
||||
## [3.6] - 2020-06-24
|
||||
### Fixed
|
||||
- Fix `session:hide()` to only send a single `Cookie` header at most as
|
||||
reported by @jharriman who also provided a fix with #103. Thank you!
|
||||
|
||||
|
||||
## [3.5] - 2020-05-22
|
||||
### Fixed
|
||||
- Fix `session:hide()` to not clear non-session request cookies that it
|
||||
seemed to do in some cases as reported by @altexy who also provided
|
||||
initial fix with #100. Thank you!
|
||||
|
||||
|
||||
## [3.4] - 2020-05-08
|
||||
### Fixed
|
||||
- Fix session_cookie_maxsize - error attempt to compare string with number,
|
||||
fixes #98, thank you @vavra5
|
||||
|
||||
### Changed
|
||||
- More robust and uniform configuration parsing
|
||||
|
||||
|
||||
## [3.3] - 2020-05-06
|
||||
### Fixed
|
||||
- Fix `set_timeouts` is only called if all parameters are available,
|
||||
should fix #96, thank you @notdodo.
|
||||
### Added
|
||||
- Add `$session_memcache_connect_timeout` configuration option
|
||||
- Add `$session_memcache_read_timeout` configuration option
|
||||
- Add `$session_memcache_send_timeout` configuration option
|
||||
- Add `$session_memcache_pool_name` configuration option
|
||||
- Add `$session_memcache_pool_backlog` configuration option
|
||||
- Add `$session_dshm_connect_timeout` configuration option
|
||||
- Add `$session_dshm_read_timeout` configuration option
|
||||
- Add `$session_dshm_send_timeout` configuration option
|
||||
- Add `$session_dshm_pool_name` configuration option
|
||||
- Add `$session_dshm_pool_backlog` configuration option
|
||||
|
||||
|
||||
## [3.2] - 2020-04-30
|
||||
### Added
|
||||
- Support for Redis clusters
|
||||
- Add `$session_redis_connect_timeout` configuration option
|
||||
- Add `$session_redis_read_timeout` configuration option
|
||||
- Add `$session_redis_send_timeout` configuration option
|
||||
- Add `$session_redis_pool_name` configuration option
|
||||
- Add `$session_redis_pool_backlog` configuration option
|
||||
- Add `$session_redis_cluster_name` configuration option
|
||||
- Add `$session_redis_cluster_dict` configuration option
|
||||
- Add `$session_redis_cluster_maxredirections` configuration option
|
||||
- Add `$session_redis_cluster_nodes` configuration option
|
||||
|
||||
|
||||
## [3.1] - 2020-03-28
|
||||
### Added
|
||||
- A more flexible way to specify custom implementations:
|
||||
`require "resty.session".new { storage = require "my.storage" }`
|
||||
|
||||
|
||||
## [3.0] - 2020-03-27
|
||||
### Fixed
|
||||
- Lock releasing is a lot more robust now
|
||||
|
||||
### Added
|
||||
- Add idletime setting (thanks @Tieske), see `session.cookie.idletime`
|
||||
- Add support for Cookie prefixes `__Host-` and `__Secure-` on Cookie
|
||||
name (see: https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-05#section-4.1.3)
|
||||
|
||||
### Changed
|
||||
- The whole codebase was refactored and simplified, especially implementing
|
||||
new storage adapters is now a lot easier
|
||||
- Redis and Memcached `spinlockwait` was changed from microseconds to milliseconds and default
|
||||
is set to `150` milliseconds,
|
||||
- Redis and Memcache will only release locks that current session instance holds
|
||||
- DSHM `session_dshm_store` was renamed to `session_dshm_region`
|
||||
- BASE64 encoding now strips the padding
|
||||
|
||||
|
||||
## [2.26] - 2020-02-11
|
||||
### Added
|
||||
- Add support for `SameSite=None` (#83) (thanks @bodewig)
|
||||
- Style changes (#77) (thanks @Tieske)
|
||||
|
||||
|
||||
## [2.25] - 2019-11-06
|
||||
### Added
|
||||
- Add SSL support for the Redis storage option (#75) (thanks @tieske)
|
||||
- DSHM storage adapter (a distributed SHM storage based on Hazelcast for Nginx)
|
||||
(thanks @grrolland)
|
||||
|
||||
|
||||
## [2.24] - 2019-07-09
|
||||
### Fixed
|
||||
- Avoid use unix socket and redis password with empty string
|
||||
- Provide session id when closing, otherwise the lock is not deleted
|
||||
|
||||
### Added
|
||||
- Added a configuration for session cookie max size (`session.cookie.maxsize`)
|
||||
|
||||
|
||||
## [2.23] - 2018-12-12
|
||||
### Added
|
||||
- Added pluggable strategies with `default` and a new `regenerate` strategy
|
||||
- Added pluggable `hmac`s
|
||||
- Added `session.close`
|
||||
- Added `ttl` to `storages`
|
||||
- Added `session.cookie.discard`, a `ttl` how long to keep old sessions when
|
||||
renewing (used by `regenerate` strategy
|
||||
|
||||
|
||||
## [2.22] - 2018-03-17
|
||||
### Fixed
|
||||
- Only sets self.cookie.secure if not defined.
|
||||
|
||||
|
||||
## [2.21] - 2018-03-16
|
||||
### Screwed
|
||||
- Forgot to bump version number.
|
||||
|
||||
|
||||
## [2.20] - 2018-03-16
|
||||
### Fixed
|
||||
- Fixes issue where check addr and check scheme could be faked.
|
||||
See also: https://github.com/bungle/lua-resty-session/issues/47
|
||||
Thanks @nielsole
|
||||
|
||||
|
||||
## [2.19] - 2017-09-19
|
||||
### Fixed
|
||||
- Fixes small bug where aes could generate invalid salt on invalid input
|
||||
that further crashes Lua with error: bad argument #2 to 'salt' (number
|
||||
expected, got no value)
|
||||
|
||||
|
||||
## [2.18] - 2017-07-10
|
||||
### Fixed
|
||||
- Automatically creates exactly 64 bits salt as required by the latest
|
||||
lua-resty-string.
|
||||
See also: https://github.com/bungle/lua-resty-session/issues/40
|
||||
Thanks @peturorri
|
||||
|
||||
|
||||
## [2.17] - 2017-06-12
|
||||
### Added
|
||||
- Added session.hide() function to hide session cookies from upstream
|
||||
on reverse proxy scenarios.
|
||||
|
||||
|
||||
## [2.16] - 2017-05-31
|
||||
### Changed
|
||||
- Delays setting the defaults until needed, allowing users to safely
|
||||
require "resty.session" in different contexts.
|
||||
|
||||
|
||||
## [2.15] - 2017-02-13
|
||||
## Added
|
||||
- Added a support for chunked cookies.
|
||||
See also: https://github.com/bungle/lua-resty-session/issues/35
|
||||
Thanks @zandbelt
|
||||
|
||||
|
||||
## [2.14] - 2016-12-16
|
||||
### Fixed
|
||||
- Lua code configuration parsing corrections (especially on boolean
|
||||
options).
|
||||
|
||||
## Added
|
||||
- Added a more natural way to pass config arguments to storage
|
||||
adapters and ciphers in Lua code.
|
||||
See also: https://github.com/bungle/lua-resty-session/issues/34
|
||||
Thanks @hanxi
|
||||
|
||||
|
||||
## [2.13] - 2016-11-21
|
||||
### Changed
|
||||
- On start we do send cookie now also if the settings have changed
|
||||
and the cookie expiry time needs to be reduced.
|
||||
|
||||
### Fixed
|
||||
- Memcache storage adapter had a missing ngx.null.
|
||||
|
||||
|
||||
## [2.12] - 2016-11-21
|
||||
### Added
|
||||
- Implemented pluggable session identifier generators.
|
||||
- Implemented random session idenfier generator.
|
||||
|
||||
### Changed
|
||||
- Now checks if headers were already sent before trying to set the
|
||||
cookie headers.
|
||||
- SSL session identifier is not checked by default anymore.
|
||||
- Lua session.identifier.length changed to session.random.length.
|
||||
- Nginx $session_identifier_length changed to $session_random_length.
|
||||
|
||||
|
||||
## [2.11] - 2016-09-30
|
||||
### Changed
|
||||
- Just another OPM release to correct the name.
|
||||
|
||||
|
||||
## [2.10] - 2016-09-29
|
||||
### Added
|
||||
- Support for the official OpenResty package manager (opm).
|
||||
|
||||
### Changed
|
||||
- Changed the change log format to keep-a-changelog.
|
||||
|
||||
|
||||
## [2.9] - 2016-09-01
|
||||
### Fixed
|
||||
- Bugfix: Weird bug where RAND_bytes was not working on Windows platform.
|
||||
Code changed to use resty.random. See Also:
|
||||
https://github.com/bungle/lua-resty-session/issues/31
|
||||
Thanks @gtuxyco
|
||||
|
||||
|
||||
## [2.8] - 2016-07-05
|
||||
### Fixed
|
||||
- Bugfix: AES Cipher used a wrong table for cipher sizes.
|
||||
See Also: https://github.com/bungle/lua-resty-session/issues/30
|
||||
Thanks @pronan
|
||||
|
||||
|
||||
## [2.7] - 2016-05-18
|
||||
### Added
|
||||
- Redis storage adapter now supports Redis authentication.
|
||||
See Also: https://github.com/bungle/lua-resty-session/pull/28
|
||||
Thanks @cheng5533062
|
||||
|
||||
|
||||
## [2.6] - 2016-04-18
|
||||
### Changed
|
||||
- Just cleanups and changed _VERSION to point correct version.
|
||||
|
||||
|
||||
## [2.5] - 2016-04-18
|
||||
### Fixed
|
||||
- session.save close argument was not defaulting to true.
|
||||
|
||||
|
||||
## [2.4] - 2016-04-17
|
||||
### Added
|
||||
- Cookie will now have SameSite attribute set as "Lax" by default.
|
||||
You can turn it off or set to "Strict" by configuration.
|
||||
|
||||
### Changed
|
||||
- Calling save will now also set session.id if the save was called
|
||||
without calling start first.
|
||||
See Also: https://github.com/bungle/lua-resty-session/issues/27
|
||||
Thanks @hcaihao
|
||||
|
||||
|
||||
## [2.3] - 2015-10-16
|
||||
### Fixed
|
||||
- Fixes issue #19 where regenerating session would throw an error
|
||||
when using cookie storage.
|
||||
See Also: https://github.com/bungle/lua-resty-session/issues/19
|
||||
Thanks @hulu1522
|
||||
|
||||
|
||||
## [2.2] - 2015-09-17
|
||||
### Changed
|
||||
- Removed all session_cipher_* deprecated settings (it was somewhat
|
||||
broken in 2.1).
|
||||
- Changed session secret to be by default 32 bytes random data
|
||||
See Also: https://github.com/bungle/lua-resty-session/issues/18
|
||||
Thanks @iain-buclaw-sociomantic
|
||||
|
||||
### Added
|
||||
- Added documentation about removed features and corrected about
|
||||
session secret size accordingly.
|
||||
|
||||
|
||||
## [2.1] - 2015-09-07
|
||||
### Added
|
||||
- Added architecture for Cipher adapter plugins.
|
||||
See Also: https://github.com/bungle/lua-resty-session/issues/16
|
||||
Thanks @mingfang
|
||||
- Implemented AES cipher adapter (just like it was before)
|
||||
- Implemented None cipher adapter (no encryption)
|
||||
- Added documentation about pluggable ciphers
|
||||
|
||||
### Changed
|
||||
- Changed JSON serializer to use cjson.safe instead
|
||||
|
||||
|
||||
## [2.0] - 2015-08-31
|
||||
### Added
|
||||
- Added architecture for Storage adapter plugins.
|
||||
See Also: https://github.com/bungle/lua-resty-session/issues/13
|
||||
- Implemented Client Side Cookie storage adapter.
|
||||
- Implemented Memcache storage adapter.
|
||||
See Also: https://github.com/bungle/lua-resty-session/pull/14
|
||||
Thanks @zandbelt
|
||||
- Implemented Redis storage adapter.
|
||||
- Implemented Shared Dictionary (shm) storage adapter.
|
||||
- Added architecture for Encoder and Decoder plugins.
|
||||
- Implemented Base 64 encoder / decoder.
|
||||
- Implemented Base 16 (hex) encoder / decoder.
|
||||
- Added architecture for Serializer plugins
|
||||
- Implemented JSON serializer.
|
||||
- Persistent cookies will now also contain Max-Age in addition to Expires.
|
||||
- Cookie domain attribute is not set anymore if not specified.
|
||||
- Added notes about using lua-resty-session with Lua code cache turned off.
|
||||
See also: https://github.com/bungle/lua-resty-session/issues/15
|
||||
Thanks @BizShuk
|
||||
|
||||
|
||||
## [1.7] - 2015-08-03
|
||||
### Added
|
||||
- Added session.open() function that only opens a session but doesn't send
|
||||
the cookie (until start is called).
|
||||
See also: https://github.com/bungle/lua-resty-session/issues/12
|
||||
Thanks @junhanamaki
|
||||
|
||||
### Fixed
|
||||
- Fixed cookie expiration time format on Firefox bug:
|
||||
https://github.com/bungle/lua-resty-session/pull/10
|
||||
Thanks @junhanamaki
|
||||
- Bugfix: Fixed an issue of overwriting a variable:
|
||||
https://github.com/bungle/lua-resty-session/pull/11
|
||||
Thanks @junhanamaki
|
||||
|
||||
|
||||
## [1.6] - 2015-05-05
|
||||
### Fixed
|
||||
- Fixed truncated cookie value bug:
|
||||
https://github.com/bungle/lua-resty-session/pull/8
|
||||
Thanks @kipras
|
||||
|
||||
|
||||
## [1.5] - 2014-11-27
|
||||
### Fixed
|
||||
- Cookies are not always "secure":
|
||||
https://github.com/bungle/lua-resty-session/issues/5
|
||||
Thanks @vladimir-smirnov-sociomantic
|
||||
|
||||
### Added
|
||||
- Added documentation about Nginx SSL/TLS configuration settings related
|
||||
to session lifetime and ssl session ids.
|
||||
|
||||
|
||||
## [1.4] - 2014-11-26
|
||||
### Fixed
|
||||
- Bugfix: Fixed an issue where session configurations did get cached
|
||||
on a module level. This issue is discussed in pull-request #4:
|
||||
https://github.com/bungle/lua-resty-session/pull/4
|
||||
Thanks @kipras.
|
||||
|
||||
### Added
|
||||
- Added session.new function.
|
||||
- Added documentation about Nginx configuration used as defaults (not read
|
||||
on every request), and documented session.new.
|
||||
|
||||
### Changed
|
||||
- session.start{ ... } (a call with config parameters) works now as expected.
|
||||
- session.start now returns additional extra boolean parameter that can be
|
||||
used to check if the session is s new session (false) or a previously
|
||||
started one (true).
|
||||
|
||||
|
||||
## [1.3] - 2014-11-14
|
||||
### Added
|
||||
- Added support for persistent sessions. See issue #2.
|
||||
- Added session.check.ssi, session.cookie.persistent and the related Nginx
|
||||
configuration variables.
|
||||
- Added Max-Age=0 to expiration code.
|
||||
|
||||
|
||||
## [1.2] - 2014-10-12
|
||||
### Fixed
|
||||
- Changed encode and decode functions to operate with correct number of
|
||||
arguments. See issue #1.
|
||||
|
||||
|
||||
## [1.1] - 2014-10-03
|
||||
### Security
|
||||
- There was a bug where additional user agent, scheme, and remote addr
|
||||
(disabled by default) was not checked.
|
||||
|
||||
### Added
|
||||
- Added _VERSION field.
|
||||
|
||||
### Changed
|
||||
- Simplied a code a lot (e.g. internal setcookie and getcookie functions are
|
||||
now cleaner). Removed a lot of unneccessary lines from session.start by
|
||||
adding configs directly to session prototype.
|
||||
|
||||
|
||||
## [1.0] - 2014-09-24
|
||||
### Added
|
||||
- LuaRocks Support via MoonRocks.
|
||||
23
deps/src/lua-resty-session/LICENSE
vendored
Normal file
23
deps/src/lua-resty-session/LICENSE
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
Copyright (c) 2014 – 2022, Aapo Talvensaari
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
4
deps/src/lua-resty-session/Makefile
vendored
Normal file
4
deps/src/lua-resty-session/Makefile
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
.PHONY: lint
|
||||
|
||||
lint:
|
||||
@luacheck -q ./lib
|
||||
1196
deps/src/lua-resty-session/README.md
vendored
Normal file
1196
deps/src/lua-resty-session/README.md
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7
deps/src/lua-resty-session/dist.ini
vendored
Normal file
7
deps/src/lua-resty-session/dist.ini
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
name = lua-resty-session
|
||||
abstract = Session Library for OpenResty - Flexible and Secure
|
||||
author = Aapo Talvensaari (@bungle)
|
||||
is_original = yes
|
||||
license = 2bsd
|
||||
repo_link = https://github.com/bungle/lua-resty-session
|
||||
requires = openresty, openresty/lua-resty-string
|
||||
771
deps/src/lua-resty-session/lib/resty/session.lua
vendored
Normal file
771
deps/src/lua-resty-session/lib/resty/session.lua
vendored
Normal file
@@ -0,0 +1,771 @@
|
||||
local require = require
|
||||
|
||||
local random = require "resty.random"
|
||||
|
||||
local ngx = ngx
|
||||
local var = ngx.var
|
||||
local time = ngx.time
|
||||
local header = ngx.header
|
||||
local http_time = ngx.http_time
|
||||
local set_header = ngx.req.set_header
|
||||
local clear_header = ngx.req.clear_header
|
||||
local concat = table.concat
|
||||
local ceil = math.ceil
|
||||
local max = math.max
|
||||
local find = string.find
|
||||
local gsub = string.gsub
|
||||
local byte = string.byte
|
||||
local sub = string.sub
|
||||
local type = type
|
||||
local pcall = pcall
|
||||
local tonumber = tonumber
|
||||
local setmetatable = setmetatable
|
||||
local getmetatable = getmetatable
|
||||
local bytes = random.bytes
|
||||
|
||||
local UNDERSCORE = byte("_")
|
||||
local EXPIRE_FLAGS = "; Expires=Thu, 01 Jan 1970 00:00:01 GMT; Max-Age=0"
|
||||
|
||||
local COOKIE_PARTS = {
|
||||
DEFAULT = {
|
||||
n = 3,
|
||||
"id",
|
||||
"expires", -- may also contain: `expires:usebefore`
|
||||
"hash"
|
||||
},
|
||||
cookie = {
|
||||
n = 4,
|
||||
"id",
|
||||
"expires", -- may also contain: `expires:usebefore`
|
||||
"data",
|
||||
"hash",
|
||||
},
|
||||
}
|
||||
|
||||
local function enabled(value)
|
||||
if value == nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
return value == true
|
||||
or value == "1"
|
||||
or value == "true"
|
||||
or value == "on"
|
||||
end
|
||||
|
||||
local function ifnil(value, default)
|
||||
if value == nil then
|
||||
return default
|
||||
end
|
||||
|
||||
return enabled(value)
|
||||
end
|
||||
|
||||
local function prequire(prefix, package, default)
|
||||
if type(package) == "table" then
|
||||
return package, package.name
|
||||
end
|
||||
|
||||
local ok, module = pcall(require, prefix .. package)
|
||||
if not ok then
|
||||
return require(prefix .. default), default
|
||||
end
|
||||
|
||||
return module, package
|
||||
end
|
||||
|
||||
local function is_session_cookie(cookie, name, name_len)
|
||||
if not cookie or cookie == "" then
|
||||
return false, nil
|
||||
end
|
||||
|
||||
cookie = gsub(cookie, "^%s+", "")
|
||||
if cookie == "" then
|
||||
return false, nil
|
||||
end
|
||||
|
||||
cookie = gsub(cookie, "%s+$", "")
|
||||
if cookie == "" then
|
||||
return false, nil
|
||||
end
|
||||
|
||||
local eq_pos = find(cookie, "=", 1, true)
|
||||
if not eq_pos then
|
||||
return false, cookie
|
||||
end
|
||||
|
||||
local cookie_name = sub(cookie, 1, eq_pos - 1)
|
||||
if cookie_name == "" then
|
||||
return false, cookie
|
||||
end
|
||||
|
||||
cookie_name = gsub(cookie_name, "%s+$", "")
|
||||
if cookie_name == "" then
|
||||
return false, cookie
|
||||
end
|
||||
|
||||
if cookie_name ~= name then
|
||||
if find(cookie_name, name, 1, true) ~= 1 then
|
||||
return false, cookie
|
||||
end
|
||||
|
||||
if byte(cookie_name, name_len + 1) ~= UNDERSCORE then
|
||||
return false, cookie
|
||||
end
|
||||
|
||||
if not tonumber(sub(cookie_name, name_len + 2), 10) then
|
||||
return false, cookie
|
||||
end
|
||||
end
|
||||
|
||||
return true, cookie
|
||||
end
|
||||
|
||||
local function set_cookie(session, value, expires)
|
||||
if ngx.headers_sent then
|
||||
return nil, "attempt to set session cookie after sending out response headers"
|
||||
end
|
||||
|
||||
value = value or ""
|
||||
|
||||
local cookie = session.cookie
|
||||
local output = {}
|
||||
|
||||
local i = 3
|
||||
|
||||
-- build cookie parameters, elements 1+2 will be set later
|
||||
if expires then
|
||||
-- we're expiring/deleting the data, so set an expiry in the past
|
||||
output[i] = EXPIRE_FLAGS
|
||||
elseif cookie.persistent then
|
||||
-- persistent cookies have an expiry
|
||||
output[i] = "; Expires=" .. http_time(session.expires) .. "; Max-Age=" .. cookie.lifetime
|
||||
else
|
||||
-- just to reserve index 3 for expiry as cookie might get smaller,
|
||||
-- and some cookies need to be expired.
|
||||
output[i] = ""
|
||||
end
|
||||
|
||||
if cookie.domain and cookie.domain ~= "localhost" and cookie.domain ~= "" then
|
||||
i = i + 1
|
||||
output[i] = "; Domain=" .. cookie.domain
|
||||
end
|
||||
|
||||
i = i + 1
|
||||
output[i] = "; Path=" .. (cookie.path or "/")
|
||||
|
||||
if cookie.samesite == "Lax"
|
||||
or cookie.samesite == "Strict"
|
||||
or cookie.samesite == "None"
|
||||
then
|
||||
i = i + 1
|
||||
output[i] = "; SameSite=" .. cookie.samesite
|
||||
end
|
||||
|
||||
if cookie.secure then
|
||||
i = i + 1
|
||||
output[i] = "; Secure"
|
||||
end
|
||||
|
||||
if cookie.httponly then
|
||||
i = i + 1
|
||||
output[i] = "; HttpOnly"
|
||||
end
|
||||
|
||||
-- How many chunks do we need?
|
||||
local cookie_parts
|
||||
local cookie_chunks
|
||||
if expires then
|
||||
-- expiring cookie, so deleting data. Do not measure data, but use
|
||||
-- existing chunk count to make sure we clear all of them
|
||||
cookie_parts = cookie.chunks or 1
|
||||
else
|
||||
-- calculate required chunks from data
|
||||
cookie_chunks = max(ceil(#value / cookie.maxsize), 1)
|
||||
cookie_parts = max(cookie_chunks, cookie.chunks or 1)
|
||||
end
|
||||
|
||||
local cookie_header = header["Set-Cookie"]
|
||||
for j = 1, cookie_parts do
|
||||
-- create numbered chunk names if required
|
||||
local chunk_name = { session.name }
|
||||
if j > 1 then
|
||||
chunk_name[2] = "_"
|
||||
chunk_name[3] = j
|
||||
chunk_name[4] = "="
|
||||
else
|
||||
chunk_name[2] = "="
|
||||
end
|
||||
chunk_name = concat(chunk_name)
|
||||
output[1] = chunk_name
|
||||
|
||||
if expires then
|
||||
-- expiring cookie, so deleting data; clear it
|
||||
output[2] = ""
|
||||
elseif j > cookie_chunks then
|
||||
-- less chunks than before, clearing excess cookies
|
||||
output[2] = ""
|
||||
output[3] = EXPIRE_FLAGS
|
||||
|
||||
else
|
||||
-- grab the piece for the current chunk
|
||||
local sp = j * cookie.maxsize - (cookie.maxsize - 1)
|
||||
if j < cookie_chunks then
|
||||
output[2] = sub(value, sp, sp + (cookie.maxsize - 1)) .. "0"
|
||||
else
|
||||
output[2] = sub(value, sp)
|
||||
end
|
||||
end
|
||||
|
||||
-- build header value and add it to the header table/string
|
||||
-- replace existing chunk-name, or append
|
||||
local cookie_content = concat(output)
|
||||
local header_type = type(cookie_header)
|
||||
if header_type == "table" then
|
||||
local found = false
|
||||
local cookie_count = #cookie_header
|
||||
for cookie_index = 1, cookie_count do
|
||||
if find(cookie_header[cookie_index], chunk_name, 1, true) == 1 then
|
||||
cookie_header[cookie_index] = cookie_content
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not found then
|
||||
cookie_header[cookie_count + 1] = cookie_content
|
||||
end
|
||||
elseif header_type == "string" and find(cookie_header, chunk_name, 1, true) ~= 1 then
|
||||
cookie_header = { cookie_header, cookie_content }
|
||||
else
|
||||
cookie_header = cookie_content
|
||||
end
|
||||
end
|
||||
|
||||
header["Set-Cookie"] = cookie_header
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function get_cookie(session, i)
|
||||
local cookie_name = { "cookie_", session.name }
|
||||
if i then
|
||||
cookie_name[3] = "_"
|
||||
cookie_name[4] = i
|
||||
else
|
||||
i = 1
|
||||
end
|
||||
|
||||
local cookie = var[concat(cookie_name)]
|
||||
if not cookie then
|
||||
return nil
|
||||
end
|
||||
|
||||
session.cookie.chunks = i
|
||||
|
||||
local cookie_size = #cookie
|
||||
if cookie_size <= session.cookie.maxsize then
|
||||
return cookie
|
||||
end
|
||||
|
||||
return concat{ sub(cookie, 1, session.cookie.maxsize), get_cookie(session, i + 1) or "" }
|
||||
end
|
||||
|
||||
local function set_usebefore(session)
|
||||
local usebefore = session.usebefore
|
||||
local idletime = session.cookie.idletime
|
||||
|
||||
if idletime == 0 then -- usebefore is disabled
|
||||
if usebefore then
|
||||
session.usebefore = nil
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
usebefore = usebefore or 0
|
||||
|
||||
local new_usebefore = session.now + idletime
|
||||
if new_usebefore - usebefore > 60 then
|
||||
session.usebefore = new_usebefore
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function save(session, close)
|
||||
session.expires = session.now + session.cookie.lifetime
|
||||
|
||||
set_usebefore(session)
|
||||
|
||||
local cookie, err = session.strategy.save(session, close)
|
||||
if not cookie then
|
||||
return nil, err or "unable to save session cookie"
|
||||
end
|
||||
|
||||
return set_cookie(session, cookie)
|
||||
end
|
||||
|
||||
local function touch(session, close)
|
||||
if set_usebefore(session) then
|
||||
-- usebefore was updated, so set cookie
|
||||
local cookie, err = session.strategy.touch(session, close)
|
||||
if not cookie then
|
||||
return nil, err or "unable to touch session cookie"
|
||||
end
|
||||
|
||||
return set_cookie(session, cookie)
|
||||
end
|
||||
|
||||
if close then
|
||||
local ok, err = session.strategy.close(session)
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function regenerate(session, flush)
|
||||
if session.strategy.destroy then
|
||||
session.strategy.destroy(session)
|
||||
elseif session.strategy.close then
|
||||
session.strategy.close(session)
|
||||
end
|
||||
|
||||
if flush then
|
||||
session.data = {}
|
||||
end
|
||||
|
||||
session.id = session:identifier()
|
||||
end
|
||||
|
||||
local secret = bytes(32, true) or bytes(32)
|
||||
local defaults
|
||||
|
||||
local function init()
|
||||
defaults = {
|
||||
name = var.session_name or "session",
|
||||
identifier = var.session_identifier or "random",
|
||||
strategy = var.session_strategy or "default",
|
||||
storage = var.session_storage or "cookie",
|
||||
serializer = var.session_serializer or "json",
|
||||
compressor = var.session_compressor or "none",
|
||||
encoder = var.session_encoder or "base64",
|
||||
cipher = var.session_cipher or "aes",
|
||||
hmac = var.session_hmac or "sha1",
|
||||
cookie = {
|
||||
path = var.session_cookie_path or "/",
|
||||
domain = var.session_cookie_domain,
|
||||
samesite = var.session_cookie_samesite or "Lax",
|
||||
secure = enabled(var.session_cookie_secure),
|
||||
httponly = enabled(var.session_cookie_httponly or true),
|
||||
persistent = enabled(var.session_cookie_persistent or false),
|
||||
discard = tonumber(var.session_cookie_discard, 10) or 10,
|
||||
renew = tonumber(var.session_cookie_renew, 10) or 600,
|
||||
lifetime = tonumber(var.session_cookie_lifetime, 10) or 3600,
|
||||
idletime = tonumber(var.session_cookie_idletime, 10) or 0,
|
||||
maxsize = tonumber(var.session_cookie_maxsize, 10) or 4000,
|
||||
|
||||
}, check = {
|
||||
ssi = enabled(var.session_check_ssi or false),
|
||||
ua = enabled(var.session_check_ua or true),
|
||||
scheme = enabled(var.session_check_scheme or true),
|
||||
addr = enabled(var.session_check_addr or false)
|
||||
}
|
||||
}
|
||||
defaults.secret = var.session_secret or secret
|
||||
end
|
||||
|
||||
local session = {
|
||||
_VERSION = "3.10"
|
||||
}
|
||||
|
||||
session.__index = session
|
||||
|
||||
function session:get_cookie()
|
||||
return get_cookie(self)
|
||||
end
|
||||
|
||||
function session:parse_cookie(value)
|
||||
local cookie
|
||||
local cookie_parts = COOKIE_PARTS[self.cookie.storage] or COOKIE_PARTS.DEFAULT
|
||||
|
||||
local count = 1
|
||||
local pos = 1
|
||||
|
||||
local p_pos = find(value, "|", 1, true)
|
||||
while p_pos do
|
||||
if count > (cookie_parts.n - 1) then
|
||||
return nil, "too many session cookie parts"
|
||||
end
|
||||
if not cookie then
|
||||
cookie = {}
|
||||
end
|
||||
|
||||
if count == 2 then
|
||||
local cookie_part = sub(value, pos, p_pos - 1)
|
||||
local c_pos = find(cookie_part, ":", 2, true)
|
||||
if c_pos then
|
||||
cookie.expires = tonumber(sub(cookie_part, 1, c_pos - 1), 10)
|
||||
if not cookie.expires then
|
||||
return nil, "invalid session cookie expiry"
|
||||
end
|
||||
|
||||
cookie.usebefore = tonumber(sub(cookie_part, c_pos + 1), 10)
|
||||
if not cookie.usebefore then
|
||||
return nil, "invalid session cookie usebefore"
|
||||
end
|
||||
else
|
||||
cookie.expires = tonumber(cookie_part, 10)
|
||||
if not cookie.expires then
|
||||
return nil, "invalid session cookie expiry"
|
||||
end
|
||||
end
|
||||
else
|
||||
local name = cookie_parts[count]
|
||||
|
||||
local cookie_part = self.encoder.decode(sub(value, pos, p_pos - 1))
|
||||
if not cookie_part then
|
||||
return nil, "unable to decode session cookie part (" .. name .. ")"
|
||||
end
|
||||
|
||||
cookie[name] = cookie_part
|
||||
end
|
||||
|
||||
count = count + 1
|
||||
pos = p_pos + 1
|
||||
|
||||
p_pos = find(value, "|", pos, true)
|
||||
end
|
||||
|
||||
if count ~= cookie_parts.n then
|
||||
return nil, "invalid number of session cookie parts"
|
||||
end
|
||||
|
||||
local name = cookie_parts[count]
|
||||
|
||||
local cookie_part = self.encoder.decode(sub(value, pos))
|
||||
if not cookie_part then
|
||||
return nil, "unable to decode session cookie part (" .. name .. ")"
|
||||
end
|
||||
|
||||
cookie[name] = cookie_part
|
||||
|
||||
if not cookie.id then
|
||||
return nil, "missing session cookie id"
|
||||
end
|
||||
|
||||
if not cookie.expires then
|
||||
return nil, "missing session cookie expiry"
|
||||
end
|
||||
|
||||
if cookie.expires <= self.now then
|
||||
return nil, "session cookie has expired"
|
||||
end
|
||||
|
||||
if cookie.usebefore and cookie.usebefore <= self.now then
|
||||
return nil, "session cookie idle time has passed"
|
||||
end
|
||||
|
||||
if not cookie.hash then
|
||||
return nil, "missing session cookie signature"
|
||||
end
|
||||
|
||||
return cookie
|
||||
end
|
||||
|
||||
function session.new(opts)
|
||||
if opts and getmetatable(opts) == session then
|
||||
return opts
|
||||
end
|
||||
|
||||
if not defaults then
|
||||
init()
|
||||
end
|
||||
|
||||
opts = type(opts) == "table" and opts or defaults
|
||||
|
||||
local cookie = opts.cookie or defaults.cookie
|
||||
local name = opts.name or defaults.name
|
||||
local sec = opts.secret or defaults.secret
|
||||
|
||||
local secure
|
||||
local path
|
||||
local domain
|
||||
if find(name, "__Host-", 1, true) == 1 then
|
||||
secure = true
|
||||
path = "/"
|
||||
else
|
||||
if find(name, "__Secure-", 1, true) == 1 then
|
||||
secure = true
|
||||
else
|
||||
secure = ifnil(cookie.secure, defaults.cookie.secure)
|
||||
end
|
||||
|
||||
domain = cookie.domain or defaults.cookie.domain
|
||||
path = cookie.path or defaults.cookie.path
|
||||
end
|
||||
|
||||
local check = opts.check or defaults.check
|
||||
|
||||
local ide, iden = prequire("resty.session.identifiers.", opts.identifier or defaults.identifier, "random")
|
||||
local ser, sern = prequire("resty.session.serializers.", opts.serializer or defaults.serializer, "json")
|
||||
local com, comn = prequire("resty.session.compressors.", opts.compressor or defaults.compressor, "none")
|
||||
local enc, encn = prequire("resty.session.encoders.", opts.encoder or defaults.encoder, "base64")
|
||||
local cip, cipn = prequire("resty.session.ciphers.", opts.cipher or defaults.cipher, "aes")
|
||||
local sto, ston = prequire("resty.session.storage.", opts.storage or defaults.storage, "cookie")
|
||||
local str, strn = prequire("resty.session.strategies.", opts.strategy or defaults.strategy, "default")
|
||||
local hma, hman = prequire("resty.session.hmac.", opts.hmac or defaults.hmac, "sha1")
|
||||
|
||||
local self = {
|
||||
now = time(),
|
||||
name = name,
|
||||
secret = sec,
|
||||
identifier = ide,
|
||||
serializer = ser,
|
||||
strategy = str,
|
||||
encoder = enc,
|
||||
hmac = hma,
|
||||
cookie = {
|
||||
storage = ston,
|
||||
encoder = enc,
|
||||
path = path,
|
||||
domain = domain,
|
||||
secure = secure,
|
||||
samesite = cookie.samesite or defaults.cookie.samesite,
|
||||
httponly = ifnil(cookie.httponly, defaults.cookie.httponly),
|
||||
persistent = ifnil(cookie.persistent, defaults.cookie.persistent),
|
||||
discard = tonumber(cookie.discard, 10) or defaults.cookie.discard,
|
||||
renew = tonumber(cookie.renew, 10) or defaults.cookie.renew,
|
||||
lifetime = tonumber(cookie.lifetime, 10) or defaults.cookie.lifetime,
|
||||
idletime = tonumber(cookie.idletime, 10) or defaults.cookie.idletime,
|
||||
maxsize = tonumber(cookie.maxsize, 10) or defaults.cookie.maxsize,
|
||||
}, check = {
|
||||
ssi = ifnil(check.ssi, defaults.check.ssi),
|
||||
ua = ifnil(check.ua, defaults.check.ua),
|
||||
scheme = ifnil(check.scheme, defaults.check.scheme),
|
||||
addr = ifnil(check.addr, defaults.check.addr),
|
||||
}
|
||||
}
|
||||
if self.cookie.idletime > 0 and self.cookie.discard > self.cookie.idletime then
|
||||
-- if using idletime, then the discard period must be less or equal
|
||||
self.cookie.discard = self.cookie.idletime
|
||||
end
|
||||
|
||||
if iden and not self[iden] then self[iden] = opts[iden] end
|
||||
if sern and not self[sern] then self[sern] = opts[sern] end
|
||||
if comn and not self[comn] then self[comn] = opts[comn] end
|
||||
if encn and not self[encn] then self[encn] = opts[encn] end
|
||||
if cipn and not self[cipn] then self[cipn] = opts[cipn] end
|
||||
if ston and not self[ston] then self[ston] = opts[ston] end
|
||||
if strn and not self[strn] then self[strn] = opts[strn] end
|
||||
if hman and not self[hman] then self[hman] = opts[hman] end
|
||||
|
||||
self.cipher = cip.new(self)
|
||||
self.storage = sto.new(self)
|
||||
self.compressor = com.new(self)
|
||||
|
||||
return setmetatable(self, session)
|
||||
end
|
||||
|
||||
function session.open(opts, keep_lock)
|
||||
local self = opts
|
||||
if self and getmetatable(self) == session then
|
||||
if self.opened then
|
||||
return self, self.present
|
||||
end
|
||||
else
|
||||
self = session.new(opts)
|
||||
end
|
||||
|
||||
if self.cookie.secure == nil then
|
||||
self.cookie.secure = var.scheme == "https" or var.https == "on"
|
||||
end
|
||||
|
||||
self.now = time()
|
||||
self.key = concat {
|
||||
self.check.ssi and var.ssl_session_id or "",
|
||||
self.check.ua and var.http_user_agent or "",
|
||||
self.check.addr and var.remote_addr or "",
|
||||
self.check.scheme and var.scheme or "",
|
||||
}
|
||||
|
||||
self.opened = true
|
||||
|
||||
local err
|
||||
local cookie = self:get_cookie()
|
||||
if cookie then
|
||||
cookie, err = self:parse_cookie(cookie)
|
||||
if cookie then
|
||||
local ok
|
||||
ok, err = self.strategy.open(self, cookie, keep_lock)
|
||||
if ok then
|
||||
return self, true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
regenerate(self, true)
|
||||
|
||||
return self, false, err
|
||||
end
|
||||
|
||||
function session.start(opts)
|
||||
if opts and getmetatable(opts) == session and opts.started then
|
||||
return opts, opts.present
|
||||
end
|
||||
|
||||
local self, present, reason = session.open(opts, true)
|
||||
|
||||
self.started = true
|
||||
|
||||
if not present then
|
||||
local ok, err = save(self)
|
||||
if not ok then
|
||||
return nil, err or "unable to save session cookie"
|
||||
end
|
||||
|
||||
return self, present, reason
|
||||
end
|
||||
|
||||
if self.strategy.start then
|
||||
local ok, err = self.strategy.start(self)
|
||||
if not ok then
|
||||
return nil, err or "unable to start session"
|
||||
end
|
||||
end
|
||||
|
||||
if self.expires - self.now < self.cookie.renew
|
||||
or self.expires > self.now + self.cookie.lifetime
|
||||
then
|
||||
local ok, err = save(self)
|
||||
if not ok then
|
||||
return nil, err or "unable to save session cookie"
|
||||
end
|
||||
else
|
||||
-- we're not saving, so we must touch to update idletime/usebefore
|
||||
local ok, err = touch(self)
|
||||
if not ok then
|
||||
return nil, err or "unable to touch session cookie"
|
||||
end
|
||||
end
|
||||
|
||||
return self, true
|
||||
end
|
||||
|
||||
function session.destroy(opts)
|
||||
if opts and getmetatable(opts) == session and opts.destroyed then
|
||||
return true
|
||||
end
|
||||
|
||||
local self, err = session.start(opts)
|
||||
if not self then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
if self.strategy.destroy then
|
||||
self.strategy.destroy(self)
|
||||
elseif self.strategy.close then
|
||||
self.strategy.close(self)
|
||||
end
|
||||
|
||||
self.data = {}
|
||||
self.present = nil
|
||||
self.opened = nil
|
||||
self.started = nil
|
||||
self.closed = true
|
||||
self.destroyed = true
|
||||
|
||||
return set_cookie(self, "", true)
|
||||
end
|
||||
|
||||
function session:regenerate(flush, close)
|
||||
close = close ~= false
|
||||
if self.strategy.regenerate then
|
||||
if flush then
|
||||
self.data = {}
|
||||
end
|
||||
|
||||
if not self.id then
|
||||
self.id = session:identifier()
|
||||
end
|
||||
else
|
||||
regenerate(self, flush)
|
||||
end
|
||||
|
||||
return save(self, close)
|
||||
end
|
||||
|
||||
function session:save(close)
|
||||
close = close ~= false
|
||||
|
||||
if not self.id then
|
||||
self.id = self:identifier()
|
||||
end
|
||||
|
||||
return save(self, close)
|
||||
end
|
||||
|
||||
function session:close()
|
||||
self.closed = true
|
||||
|
||||
if self.strategy.close then
|
||||
return self.strategy.close(self)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function session:hide()
|
||||
local cookies = var.http_cookie
|
||||
if not cookies or cookies == "" then
|
||||
return
|
||||
end
|
||||
|
||||
local results = {}
|
||||
local name = self.name
|
||||
local name_len = #name
|
||||
local found
|
||||
local i = 1
|
||||
local j = 0
|
||||
local sc_pos = find(cookies, ";", i, true)
|
||||
while sc_pos do
|
||||
local isc, cookie = is_session_cookie(sub(cookies, i, sc_pos - 1), name, name_len)
|
||||
if isc then
|
||||
found = true
|
||||
elseif cookie then
|
||||
j = j + 1
|
||||
results[j] = cookie
|
||||
end
|
||||
|
||||
i = sc_pos + 1
|
||||
sc_pos = find(cookies, ";", i, true)
|
||||
end
|
||||
|
||||
local isc, cookie
|
||||
if i == 1 then
|
||||
isc, cookie = is_session_cookie(cookies, name, name_len)
|
||||
else
|
||||
isc, cookie = is_session_cookie(sub(cookies, i), name, name_len)
|
||||
end
|
||||
|
||||
if not isc and cookie then
|
||||
if not found then
|
||||
return
|
||||
end
|
||||
|
||||
j = j + 1
|
||||
results[j] = cookie
|
||||
end
|
||||
|
||||
if j == 0 then
|
||||
clear_header("Cookie")
|
||||
else
|
||||
set_header("Cookie", concat(results, "; ", 1, j))
|
||||
end
|
||||
end
|
||||
|
||||
return session
|
||||
113
deps/src/lua-resty-session/lib/resty/session/ciphers/aes.lua
vendored
Normal file
113
deps/src/lua-resty-session/lib/resty/session/ciphers/aes.lua
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
local aes = require "resty.aes"
|
||||
|
||||
local setmetatable = setmetatable
|
||||
local tonumber = tonumber
|
||||
local ceil = math.ceil
|
||||
local var = ngx.var
|
||||
local sub = string.sub
|
||||
local rep = string.rep
|
||||
|
||||
local HASHES = aes.hash
|
||||
|
||||
local CIPHER_MODES = {
|
||||
ecb = "ecb",
|
||||
cbc = "cbc",
|
||||
cfb1 = "cfb1",
|
||||
cfb8 = "cfb8",
|
||||
cfb128 = "cfb128",
|
||||
ofb = "ofb",
|
||||
ctr = "ctr",
|
||||
gcm = "gcm",
|
||||
}
|
||||
|
||||
local CIPHER_SIZES = {
|
||||
[128] = 128,
|
||||
[192] = 192,
|
||||
[256] = 256,
|
||||
}
|
||||
|
||||
local defaults = {
|
||||
size = CIPHER_SIZES[tonumber(var.session_aes_size, 10)] or 256,
|
||||
mode = CIPHER_MODES[var.session_aes_mode] or "cbc",
|
||||
hash = HASHES[var.session_aes_hash] or HASHES.sha512,
|
||||
rounds = tonumber(var.session_aes_rounds, 10) or 1,
|
||||
}
|
||||
|
||||
local function adjust_salt(salt)
|
||||
if not salt then
|
||||
return nil
|
||||
end
|
||||
|
||||
local z = #salt
|
||||
if z < 8 then
|
||||
return sub(rep(salt, ceil(8 / z)), 1, 8)
|
||||
end
|
||||
if z > 8 then
|
||||
return sub(salt, 1, 8)
|
||||
end
|
||||
|
||||
return salt
|
||||
end
|
||||
|
||||
local function get_cipher(self, key, salt)
|
||||
local mode = aes.cipher(self.size, self.mode)
|
||||
if not mode then
|
||||
return nil, "invalid cipher mode " .. self.mode .. "(" .. self.size .. ")"
|
||||
end
|
||||
|
||||
return aes:new(key, adjust_salt(salt), mode, self.hash, self.rounds)
|
||||
end
|
||||
|
||||
local cipher = {}
|
||||
|
||||
cipher.__index = cipher
|
||||
|
||||
function cipher.new(session)
|
||||
local config = session.aes or defaults
|
||||
return setmetatable({
|
||||
size = CIPHER_SIZES[tonumber(config.size, 10)] or defaults.size,
|
||||
mode = CIPHER_MODES[config.mode] or defaults.mode,
|
||||
hash = HASHES[config.hash] or defaults.hash,
|
||||
rounds = tonumber(config.rounds, 10) or defaults.rounds,
|
||||
}, cipher)
|
||||
end
|
||||
|
||||
function cipher:encrypt(data, key, salt, _)
|
||||
local cip, err = get_cipher(self, key, salt)
|
||||
if not cip then
|
||||
return nil, err or "unable to aes encrypt data"
|
||||
end
|
||||
|
||||
local encrypted_data
|
||||
encrypted_data, err = cip:encrypt(data)
|
||||
if not encrypted_data then
|
||||
return nil, err or "aes encryption failed"
|
||||
end
|
||||
|
||||
if self.mode == "gcm" then
|
||||
return encrypted_data[1], nil, encrypted_data[2]
|
||||
end
|
||||
|
||||
return encrypted_data
|
||||
end
|
||||
|
||||
function cipher:decrypt(data, key, salt, _, tag)
|
||||
local cip, err = get_cipher(self, key, salt)
|
||||
if not cip then
|
||||
return nil, err or "unable to aes decrypt data"
|
||||
end
|
||||
|
||||
local decrypted_data
|
||||
decrypted_data, err = cip:decrypt(data, tag)
|
||||
if not decrypted_data then
|
||||
return nil, err or "aes decryption failed"
|
||||
end
|
||||
|
||||
if self.mode == "gcm" then
|
||||
return decrypted_data, nil, tag
|
||||
end
|
||||
|
||||
return decrypted_data
|
||||
end
|
||||
|
||||
return cipher
|
||||
15
deps/src/lua-resty-session/lib/resty/session/ciphers/none.lua
vendored
Normal file
15
deps/src/lua-resty-session/lib/resty/session/ciphers/none.lua
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
local cipher = {}
|
||||
|
||||
function cipher.new()
|
||||
return cipher
|
||||
end
|
||||
|
||||
function cipher.encrypt(_, data, _, _)
|
||||
return data
|
||||
end
|
||||
|
||||
function cipher.decrypt(_, data, _, _, _)
|
||||
return data
|
||||
end
|
||||
|
||||
return cipher
|
||||
15
deps/src/lua-resty-session/lib/resty/session/compressors/none.lua
vendored
Normal file
15
deps/src/lua-resty-session/lib/resty/session/compressors/none.lua
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
local compressor = {}
|
||||
|
||||
function compressor.new()
|
||||
return compressor
|
||||
end
|
||||
|
||||
function compressor.compress(_, data)
|
||||
return data
|
||||
end
|
||||
|
||||
function compressor.decompress(_, data)
|
||||
return data
|
||||
end
|
||||
|
||||
return compressor
|
||||
43
deps/src/lua-resty-session/lib/resty/session/compressors/zlib.lua
vendored
Normal file
43
deps/src/lua-resty-session/lib/resty/session/compressors/zlib.lua
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
local zlib = require "ffi-zlib"
|
||||
local sio = require "pl.stringio"
|
||||
|
||||
local concat = table.concat
|
||||
|
||||
local function gzip(func, input)
|
||||
local stream = sio.open(input)
|
||||
local output = {}
|
||||
local n = 0
|
||||
|
||||
local ok, err = func(function(size)
|
||||
return stream:read(size)
|
||||
end, function(data)
|
||||
n = n + 1
|
||||
output[n] = data
|
||||
end, 8192)
|
||||
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
if n == 0 then
|
||||
return ""
|
||||
end
|
||||
|
||||
return concat(output, nil, 1, n)
|
||||
end
|
||||
|
||||
local compressor = {}
|
||||
|
||||
function compressor.new()
|
||||
return compressor
|
||||
end
|
||||
|
||||
function compressor.compress(_, data)
|
||||
return gzip(zlib.deflateGzip, data)
|
||||
end
|
||||
|
||||
function compressor.decompress(_, data)
|
||||
return gzip(zlib.inflateGzip, data)
|
||||
end
|
||||
|
||||
return compressor
|
||||
29
deps/src/lua-resty-session/lib/resty/session/encoders/base16.lua
vendored
Normal file
29
deps/src/lua-resty-session/lib/resty/session/encoders/base16.lua
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
local to_hex = require "resty.string".to_hex
|
||||
|
||||
local tonumber = tonumber
|
||||
local gsub = string.gsub
|
||||
local char = string.char
|
||||
|
||||
local function chr(c)
|
||||
return char(tonumber(c, 16) or 0)
|
||||
end
|
||||
|
||||
local encoder = {}
|
||||
|
||||
function encoder.encode(value)
|
||||
if not value then
|
||||
return nil, "unable to base16 encode value"
|
||||
end
|
||||
|
||||
return to_hex(value)
|
||||
end
|
||||
|
||||
function encoder.decode(value)
|
||||
if not value then
|
||||
return nil, "unable to base16 decode value"
|
||||
end
|
||||
|
||||
return (gsub(value, "..", chr))
|
||||
end
|
||||
|
||||
return encoder
|
||||
39
deps/src/lua-resty-session/lib/resty/session/encoders/base64.lua
vendored
Normal file
39
deps/src/lua-resty-session/lib/resty/session/encoders/base64.lua
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
local encode_base64 = ngx.encode_base64
|
||||
local decode_base64 = ngx.decode_base64
|
||||
|
||||
local gsub = string.gsub
|
||||
|
||||
local ENCODE_CHARS = {
|
||||
["+"] = "-",
|
||||
["/"] = "_",
|
||||
}
|
||||
|
||||
local DECODE_CHARS = {
|
||||
["-"] = "+",
|
||||
["_"] = "/",
|
||||
}
|
||||
|
||||
local encoder = {}
|
||||
|
||||
function encoder.encode(value)
|
||||
if not value then
|
||||
return nil, "unable to base64 encode value"
|
||||
end
|
||||
|
||||
local encoded = encode_base64(value, true)
|
||||
if not encoded then
|
||||
return nil, "unable to base64 encode value"
|
||||
end
|
||||
|
||||
return gsub(encoded, "[+/]", ENCODE_CHARS)
|
||||
end
|
||||
|
||||
function encoder.decode(value)
|
||||
if not value then
|
||||
return nil, "unable to base64 decode value"
|
||||
end
|
||||
|
||||
return decode_base64((gsub(value, "[-_]", DECODE_CHARS)))
|
||||
end
|
||||
|
||||
return encoder
|
||||
1
deps/src/lua-resty-session/lib/resty/session/encoders/hex.lua
vendored
Normal file
1
deps/src/lua-resty-session/lib/resty/session/encoders/hex.lua
vendored
Normal file
@@ -0,0 +1 @@
|
||||
return require "resty.session.encoders.base16"
|
||||
1
deps/src/lua-resty-session/lib/resty/session/hmac/sha1.lua
vendored
Normal file
1
deps/src/lua-resty-session/lib/resty/session/hmac/sha1.lua
vendored
Normal file
@@ -0,0 +1 @@
|
||||
return ngx.hmac_sha1
|
||||
13
deps/src/lua-resty-session/lib/resty/session/identifiers/random.lua
vendored
Normal file
13
deps/src/lua-resty-session/lib/resty/session/identifiers/random.lua
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
local tonumber = tonumber
|
||||
local random = require "resty.random".bytes
|
||||
local var = ngx.var
|
||||
|
||||
local defaults = {
|
||||
length = tonumber(var.session_random_length, 10) or 16
|
||||
}
|
||||
|
||||
return function(session)
|
||||
local config = session.random or defaults
|
||||
local length = tonumber(config.length, 10) or defaults.length
|
||||
return random(length, true) or random(length)
|
||||
end
|
||||
6
deps/src/lua-resty-session/lib/resty/session/serializers/json.lua
vendored
Normal file
6
deps/src/lua-resty-session/lib/resty/session/serializers/json.lua
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
local json = require "cjson.safe"
|
||||
|
||||
return {
|
||||
serialize = json.encode,
|
||||
deserialize = json.decode,
|
||||
}
|
||||
7
deps/src/lua-resty-session/lib/resty/session/storage/cookie.lua
vendored
Normal file
7
deps/src/lua-resty-session/lib/resty/session/storage/cookie.lua
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
local storage = {}
|
||||
|
||||
function storage.new()
|
||||
return storage
|
||||
end
|
||||
|
||||
return storage
|
||||
163
deps/src/lua-resty-session/lib/resty/session/storage/dshm.lua
vendored
Normal file
163
deps/src/lua-resty-session/lib/resty/session/storage/dshm.lua
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
local dshm = require "resty.dshm"
|
||||
|
||||
local setmetatable = setmetatable
|
||||
local tonumber = tonumber
|
||||
local concat = table.concat
|
||||
local var = ngx.var
|
||||
|
||||
local defaults = {
|
||||
region = var.session_dshm_region or "sessions",
|
||||
connect_timeout = tonumber(var.session_dshm_connect_timeout, 10),
|
||||
read_timeout = tonumber(var.session_dshm_read_timeout, 10),
|
||||
send_timeout = tonumber(var.session_dshm_send_timeout, 10),
|
||||
host = var.session_dshm_host or "127.0.0.1",
|
||||
port = tonumber(var.session_dshm_port, 10) or 4321,
|
||||
pool = {
|
||||
name = var.session_dshm_pool_name,
|
||||
size = tonumber(var.session_dshm_pool_size, 10) or 100,
|
||||
timeout = tonumber(var.session_dshm_pool_timeout, 10) or 1000,
|
||||
backlog = tonumber(var.session_dshm_pool_backlog, 10),
|
||||
},
|
||||
}
|
||||
|
||||
local storage = {}
|
||||
|
||||
storage.__index = storage
|
||||
|
||||
function storage.new(session)
|
||||
local config = session.dshm or defaults
|
||||
local pool = config.pool or defaults.pool
|
||||
|
||||
local connect_timeout = tonumber(config.connect_timeout, 10) or defaults.connect_timeout
|
||||
|
||||
local store = dshm:new()
|
||||
if store.set_timeouts then
|
||||
local send_timeout = tonumber(config.send_timeout, 10) or defaults.send_timeout
|
||||
local read_timeout = tonumber(config.read_timeout, 10) or defaults.read_timeout
|
||||
|
||||
if connect_timeout then
|
||||
if send_timeout and read_timeout then
|
||||
store:set_timeouts(connect_timeout, send_timeout, read_timeout)
|
||||
else
|
||||
store:set_timeout(connect_timeout)
|
||||
end
|
||||
end
|
||||
|
||||
elseif store.set_timeout and connect_timeout then
|
||||
store:set_timeout(connect_timeout)
|
||||
end
|
||||
|
||||
|
||||
local self = {
|
||||
store = store,
|
||||
encoder = session.encoder,
|
||||
region = config.region or defaults.region,
|
||||
host = config.host or defaults.host,
|
||||
port = tonumber(config.port, 10) or defaults.port,
|
||||
pool_timeout = tonumber(pool.timeout, 10) or defaults.pool.timeout,
|
||||
connect_opts = {
|
||||
pool = pool.name or defaults.pool.name,
|
||||
pool_size = tonumber(pool.size, 10) or defaults.pool.size,
|
||||
backlog = tonumber(pool.backlog, 10) or defaults.pool.backlog,
|
||||
},
|
||||
}
|
||||
|
||||
return setmetatable(self, storage)
|
||||
end
|
||||
|
||||
function storage:connect()
|
||||
return self.store:connect(self.host, self.port, self.connect_opts)
|
||||
end
|
||||
|
||||
function storage:set_keepalive()
|
||||
return self.store:set_keepalive(self.pool_timeout)
|
||||
end
|
||||
|
||||
function storage:key(id)
|
||||
return concat({ self.region, id }, "::")
|
||||
end
|
||||
|
||||
function storage:set(key, ttl, data)
|
||||
local ok, err = self:connect()
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
data, err = self.encoder.encode(data)
|
||||
|
||||
if not data then
|
||||
self:set_keepalive()
|
||||
return nil, err
|
||||
end
|
||||
|
||||
ok, err = self.store:set(key, data, ttl)
|
||||
|
||||
self:set_keepalive()
|
||||
|
||||
return ok, err
|
||||
end
|
||||
|
||||
function storage:get(key)
|
||||
local ok, err = self:connect()
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local data
|
||||
data, err = self.store:get(key)
|
||||
if data then
|
||||
data, err = self.encoder.decode(data)
|
||||
end
|
||||
|
||||
self:set_keepalive()
|
||||
|
||||
return data, err
|
||||
end
|
||||
|
||||
function storage:delete(key)
|
||||
local ok, err = self:connect()
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
ok, err = self.store:delete(key)
|
||||
|
||||
self:set_keepalive()
|
||||
|
||||
return ok, err
|
||||
end
|
||||
|
||||
function storage:touch(key, ttl)
|
||||
local ok, err = self:connect()
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
ok, err = self.store:touch(key, ttl)
|
||||
|
||||
self:set_keepalive()
|
||||
|
||||
return ok, err
|
||||
end
|
||||
|
||||
function storage:open(id)
|
||||
local key = self:key(id)
|
||||
return self:get(key)
|
||||
end
|
||||
|
||||
function storage:save(id, ttl, data)
|
||||
local key = self:key(id)
|
||||
return self:set(key, ttl, data)
|
||||
end
|
||||
|
||||
function storage:destroy(id)
|
||||
local key = self:key(id)
|
||||
return self:delete(key)
|
||||
end
|
||||
|
||||
function storage:ttl(id, ttl)
|
||||
local key = self:key(id)
|
||||
return self:touch(key, ttl)
|
||||
end
|
||||
|
||||
return storage
|
||||
303
deps/src/lua-resty-session/lib/resty/session/storage/memcache.lua
vendored
Normal file
303
deps/src/lua-resty-session/lib/resty/session/storage/memcache.lua
vendored
Normal file
@@ -0,0 +1,303 @@
|
||||
local memcached = require "resty.memcached"
|
||||
local setmetatable = setmetatable
|
||||
local tonumber = tonumber
|
||||
local concat = table.concat
|
||||
local sleep = ngx.sleep
|
||||
local null = ngx.null
|
||||
local var = ngx.var
|
||||
|
||||
local function enabled(value)
|
||||
if value == nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
return value == true
|
||||
or value == "1"
|
||||
or value == "true"
|
||||
or value == "on"
|
||||
end
|
||||
|
||||
local function ifnil(value, default)
|
||||
if value == nil then
|
||||
return default
|
||||
end
|
||||
|
||||
return enabled(value)
|
||||
end
|
||||
|
||||
local defaults = {
|
||||
prefix = var.session_memcache_prefix or "sessions",
|
||||
socket = var.session_memcache_socket,
|
||||
host = var.session_memcache_host or "127.0.0.1",
|
||||
uselocking = enabled(var.session_memcache_uselocking or true),
|
||||
connect_timeout = tonumber(var.session_memcache_connect_timeout, 10),
|
||||
read_timeout = tonumber(var.session_memcache_read_timeout, 10),
|
||||
send_timeout = tonumber(var.session_memcache_send_timeout, 10),
|
||||
port = tonumber(var.session_memcache_port, 10) or 11211,
|
||||
spinlockwait = tonumber(var.session_memcache_spinlockwait, 10) or 150,
|
||||
maxlockwait = tonumber(var.session_memcache_maxlockwait, 10) or 30,
|
||||
pool = {
|
||||
name = var.session_memcache_pool_name,
|
||||
timeout = tonumber(var.session_memcache_pool_timeout, 10),
|
||||
size = tonumber(var.session_memcache_pool_size, 10),
|
||||
backlog = tonumber(var.session_memcache_pool_backlog, 10),
|
||||
},
|
||||
}
|
||||
|
||||
local storage = {}
|
||||
|
||||
storage.__index = storage
|
||||
|
||||
function storage.new(session)
|
||||
local config = session.memcache or defaults
|
||||
local pool = config.pool or defaults.pool
|
||||
local locking = ifnil(config.uselocking, defaults.uselocking)
|
||||
|
||||
local connect_timeout = tonumber(config.connect_timeout, 10) or defaults.connect_timeout
|
||||
|
||||
local memcache = memcached:new()
|
||||
if memcache.set_timeouts then
|
||||
local send_timeout = tonumber(config.send_timeout, 10) or defaults.send_timeout
|
||||
local read_timeout = tonumber(config.read_timeout, 10) or defaults.read_timeout
|
||||
|
||||
if connect_timeout then
|
||||
if send_timeout and read_timeout then
|
||||
memcache:set_timeouts(connect_timeout, send_timeout, read_timeout)
|
||||
else
|
||||
memcache:set_timeout(connect_timeout)
|
||||
end
|
||||
end
|
||||
|
||||
elseif memcache.set_timeout and connect_timeout then
|
||||
memcache:set_timeout(connect_timeout)
|
||||
end
|
||||
|
||||
local self = {
|
||||
memcache = memcache,
|
||||
prefix = config.prefix or defaults.prefix,
|
||||
uselocking = locking,
|
||||
spinlockwait = tonumber(config.spinlockwait, 10) or defaults.spinlockwait,
|
||||
maxlockwait = tonumber(config.maxlockwait, 10) or defaults.maxlockwait,
|
||||
pool_timeout = tonumber(pool.timeout, 10) or defaults.pool.timeout,
|
||||
connect_opts = {
|
||||
pool = pool.name or defaults.pool.name,
|
||||
pool_size = tonumber(pool.size, 10) or defaults.pool.size,
|
||||
backlog = tonumber(pool.backlog, 10) or defaults.pool.backlog,
|
||||
},
|
||||
}
|
||||
|
||||
local socket = config.socket or defaults.socket
|
||||
if socket and socket ~= "" then
|
||||
self.socket = socket
|
||||
else
|
||||
self.host = config.host or defaults.host
|
||||
self.port = config.port or defaults.port
|
||||
end
|
||||
|
||||
return setmetatable(self, storage)
|
||||
end
|
||||
|
||||
function storage:connect()
|
||||
local socket = self.socket
|
||||
if socket then
|
||||
return self.memcache:connect(socket, self.connect_opts)
|
||||
end
|
||||
return self.memcache:connect(self.host, self.port, self.connect_opts)
|
||||
end
|
||||
|
||||
function storage:set_keepalive()
|
||||
return self.memcache:set_keepalive(self.pool_timeout)
|
||||
end
|
||||
|
||||
function storage:key(id)
|
||||
return concat({ self.prefix, id }, ":" )
|
||||
end
|
||||
|
||||
function storage:lock(key)
|
||||
if not self.uselocking or self.locked then
|
||||
return true
|
||||
end
|
||||
|
||||
if not self.token then
|
||||
self.token = var.request_id
|
||||
end
|
||||
|
||||
local lock_key = concat({ key, "lock" }, "." )
|
||||
local lock_ttl = self.maxlockwait + 1
|
||||
local attempts = (1000 / self.spinlockwait) * self.maxlockwait
|
||||
local waittime = self.spinlockwait / 1000
|
||||
|
||||
for _ = 1, attempts do
|
||||
local ok = self.memcache:add(lock_key, self.token, lock_ttl)
|
||||
if ok then
|
||||
self.locked = true
|
||||
return true
|
||||
end
|
||||
|
||||
sleep(waittime)
|
||||
end
|
||||
|
||||
return false, "unable to acquire a session lock"
|
||||
end
|
||||
|
||||
function storage:unlock(key)
|
||||
if not self.uselocking or not self.locked then
|
||||
return true
|
||||
end
|
||||
|
||||
local lock_key = concat({ key, "lock" }, "." )
|
||||
local token = self:get(lock_key)
|
||||
|
||||
if token == self.token then
|
||||
self.memcache:delete(lock_key)
|
||||
self.locked = nil
|
||||
end
|
||||
end
|
||||
|
||||
function storage:get(key)
|
||||
local data, err = self.memcache:get(key)
|
||||
if not data then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
if data == null then
|
||||
return nil
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
function storage:set(key, data, ttl)
|
||||
return self.memcache:set(key, data, ttl)
|
||||
end
|
||||
|
||||
function storage:expire(key, ttl)
|
||||
return self.memcache:touch(key, ttl)
|
||||
end
|
||||
|
||||
function storage:delete(key)
|
||||
return self.memcache:delete(key)
|
||||
end
|
||||
|
||||
function storage:open(id, keep_lock)
|
||||
local ok, err = self:connect()
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local key = self:key(id)
|
||||
|
||||
ok, err = self:lock(key)
|
||||
if not ok then
|
||||
self:set_keepalive()
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local data
|
||||
data, err = self:get(key)
|
||||
|
||||
if err or not data or not keep_lock then
|
||||
self:unlock(key)
|
||||
end
|
||||
|
||||
self:set_keepalive()
|
||||
|
||||
return data, err
|
||||
end
|
||||
|
||||
function storage:start(id)
|
||||
if not self.uselocking or not self.locked then
|
||||
return true
|
||||
end
|
||||
|
||||
local ok, err = self:connect()
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local key = self:key(id)
|
||||
|
||||
ok, err = self:lock(key)
|
||||
|
||||
self:set_keepalive()
|
||||
|
||||
return ok, err
|
||||
end
|
||||
|
||||
function storage:save(id, ttl, data, close)
|
||||
local ok, err = self:connect()
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local key = self:key(id)
|
||||
|
||||
ok, err = self:set(key, data, ttl)
|
||||
|
||||
if close then
|
||||
self:unlock(key)
|
||||
end
|
||||
|
||||
self:set_keepalive()
|
||||
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function storage:close(id)
|
||||
if not self.uselocking or not self.locked then
|
||||
return true
|
||||
end
|
||||
|
||||
local ok, err = self:connect()
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local key = self:key(id)
|
||||
|
||||
self:unlock(key)
|
||||
self:set_keepalive()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function storage:destroy(id)
|
||||
local ok, err = self:connect()
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local key = self:key(id)
|
||||
|
||||
ok, err = self:delete(key)
|
||||
|
||||
self:unlock(key)
|
||||
self:set_keepalive()
|
||||
|
||||
return ok, err
|
||||
end
|
||||
|
||||
function storage:ttl(id, ttl, close)
|
||||
local ok, err = self:connect()
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local key = self:key(id)
|
||||
|
||||
ok, err = self:expire(key, ttl)
|
||||
|
||||
if close then
|
||||
self:unlock(key)
|
||||
end
|
||||
|
||||
self:set_keepalive()
|
||||
|
||||
return ok, err
|
||||
end
|
||||
|
||||
return storage
|
||||
1
deps/src/lua-resty-session/lib/resty/session/storage/memcached.lua
vendored
Normal file
1
deps/src/lua-resty-session/lib/resty/session/storage/memcached.lua
vendored
Normal file
@@ -0,0 +1 @@
|
||||
return require "resty.session.storage.memcache"
|
||||
478
deps/src/lua-resty-session/lib/resty/session/storage/redis.lua
vendored
Normal file
478
deps/src/lua-resty-session/lib/resty/session/storage/redis.lua
vendored
Normal file
@@ -0,0 +1,478 @@
|
||||
local setmetatable = setmetatable
|
||||
local tonumber = tonumber
|
||||
local type = type
|
||||
local reverse = string.reverse
|
||||
local gmatch = string.gmatch
|
||||
local find = string.find
|
||||
local byte = string.byte
|
||||
local sub = string.sub
|
||||
local concat = table.concat
|
||||
local sleep = ngx.sleep
|
||||
local null = ngx.null
|
||||
local var = ngx.var
|
||||
|
||||
local LB = byte("[")
|
||||
local RB = byte("]")
|
||||
|
||||
local function parse_cluster_nodes(nodes)
|
||||
if not nodes or nodes == "" then
|
||||
return nil
|
||||
end
|
||||
|
||||
if type(nodes) == "table" then
|
||||
return nodes
|
||||
end
|
||||
|
||||
local addrs
|
||||
local i
|
||||
for node in gmatch(nodes, "%S+") do
|
||||
local ip = node
|
||||
local port = 6379
|
||||
local pos = find(reverse(ip), ":", 2, true)
|
||||
if pos then
|
||||
local p = tonumber(sub(ip, -pos + 1), 10)
|
||||
if p >= 1 and p <= 65535 then
|
||||
local addr = sub(ip, 1, -pos - 1)
|
||||
if find(addr, ":", 1, true) then
|
||||
if byte(addr, -1) == RB then
|
||||
ip = addr
|
||||
port = p
|
||||
end
|
||||
|
||||
else
|
||||
ip = addr
|
||||
port = p
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if byte(ip, 1, 1) == LB then
|
||||
ip = sub(ip, 2)
|
||||
end
|
||||
|
||||
if byte(ip, -1) == RB then
|
||||
ip = sub(ip, 1, -2)
|
||||
end
|
||||
|
||||
if not addrs then
|
||||
i = 1
|
||||
addrs = {{
|
||||
ip = ip,
|
||||
port = port,
|
||||
}}
|
||||
else
|
||||
i = i + 1
|
||||
addrs[i] = {
|
||||
ip = ip,
|
||||
port = port,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
if not i then
|
||||
return
|
||||
end
|
||||
|
||||
return addrs
|
||||
end
|
||||
|
||||
local redis_single = require "resty.redis"
|
||||
local redis_cluster
|
||||
do
|
||||
local pcall = pcall
|
||||
local require = require
|
||||
local ok
|
||||
ok, redis_cluster = pcall(require, "resty.rediscluster")
|
||||
if not ok then
|
||||
ok, redis_cluster = pcall(require, "rediscluster")
|
||||
if not ok then
|
||||
redis_cluster = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local UNLOCK = [[
|
||||
if redis.call("GET", KEYS[1]) == ARGV[1] then
|
||||
return redis.call("DEL", KEYS[1])
|
||||
else
|
||||
return 0
|
||||
end
|
||||
]]
|
||||
|
||||
local function enabled(value)
|
||||
if value == nil then return nil end
|
||||
return value == true or (value == "1" or value == "true" or value == "on")
|
||||
end
|
||||
|
||||
local function ifnil(value, default)
|
||||
if value == nil then
|
||||
return default
|
||||
end
|
||||
|
||||
return enabled(value)
|
||||
end
|
||||
|
||||
local defaults = {
|
||||
prefix = var.session_redis_prefix or "sessions",
|
||||
socket = var.session_redis_socket,
|
||||
host = var.session_redis_host or "127.0.0.1",
|
||||
username = var.session_redis_username,
|
||||
password = var.session_redis_password or var.session_redis_auth,
|
||||
server_name = var.session_redis_server_name,
|
||||
ssl = enabled(var.session_redis_ssl) or false,
|
||||
ssl_verify = enabled(var.session_redis_ssl_verify) or false,
|
||||
uselocking = enabled(var.session_redis_uselocking or true),
|
||||
port = tonumber(var.session_redis_port, 10) or 6379,
|
||||
database = tonumber(var.session_redis_database, 10) or 0,
|
||||
connect_timeout = tonumber(var.session_redis_connect_timeout, 10),
|
||||
read_timeout = tonumber(var.session_redis_read_timeout, 10),
|
||||
send_timeout = tonumber(var.session_redis_send_timeout, 10),
|
||||
spinlockwait = tonumber(var.session_redis_spinlockwait, 10) or 150,
|
||||
maxlockwait = tonumber(var.session_redis_maxlockwait, 10) or 30,
|
||||
pool = {
|
||||
name = var.session_redis_pool_name,
|
||||
timeout = tonumber(var.session_redis_pool_timeout, 10),
|
||||
size = tonumber(var.session_redis_pool_size, 10),
|
||||
backlog = tonumber(var.session_redis_pool_backlog, 10),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
if redis_cluster then
|
||||
defaults.cluster = {
|
||||
name = var.session_redis_cluster_name,
|
||||
dict = var.session_redis_cluster_dict,
|
||||
maxredirections = tonumber(var.session_redis_cluster_maxredirections, 10),
|
||||
nodes = parse_cluster_nodes(var.session_redis_cluster_nodes),
|
||||
}
|
||||
end
|
||||
|
||||
local storage = {}
|
||||
|
||||
storage.__index = storage
|
||||
|
||||
function storage.new(session)
|
||||
local config = session.redis or defaults
|
||||
local pool = config.pool or defaults.pool
|
||||
local cluster = config.cluster or defaults.cluster
|
||||
local locking = ifnil(config.uselocking, defaults.uselocking)
|
||||
|
||||
local self = {
|
||||
prefix = config.prefix or defaults.prefix,
|
||||
uselocking = locking,
|
||||
spinlockwait = tonumber(config.spinlockwait, 10) or defaults.spinlockwait,
|
||||
maxlockwait = tonumber(config.maxlockwait, 10) or defaults.maxlockwait,
|
||||
}
|
||||
|
||||
local username = config.username or defaults.username
|
||||
if username == "" then
|
||||
username = nil
|
||||
end
|
||||
local password = config.password or config.auth or defaults.password
|
||||
if password == "" then
|
||||
password = nil
|
||||
end
|
||||
|
||||
local connect_timeout = tonumber(config.connect_timeout, 10) or defaults.connect_timeout
|
||||
|
||||
local cluster_nodes
|
||||
if redis_cluster then
|
||||
cluster_nodes = parse_cluster_nodes(cluster.nodes or defaults.cluster.nodes)
|
||||
end
|
||||
|
||||
local connect_opts = {
|
||||
pool = pool.name or defaults.pool.name,
|
||||
pool_size = tonumber(pool.size, 10) or defaults.pool.size,
|
||||
backlog = tonumber(pool.backlog, 10) or defaults.pool.backlog,
|
||||
server_name = config.server_name or defaults.server_name,
|
||||
ssl = ifnil(config.ssl, defaults.ssl),
|
||||
ssl_verify = ifnil(config.ssl_verify, defaults.ssl_verify),
|
||||
}
|
||||
|
||||
if cluster_nodes then
|
||||
self.redis = redis_cluster:new({
|
||||
name = cluster.name or defaults.cluster.name,
|
||||
dict_name = cluster.dict or defaults.cluster.dict,
|
||||
username = var.session_redis_username,
|
||||
password = var.session_redis_password or defaults.password,
|
||||
connection_timout = connect_timeout, -- typo in library
|
||||
connection_timeout = connect_timeout,
|
||||
keepalive_timeout = tonumber(pool.timeout, 10) or defaults.pool.timeout,
|
||||
keepalive_cons = tonumber(pool.size, 10) or defaults.pool.size,
|
||||
max_redirection = tonumber(cluster.maxredirections, 10) or defaults.cluster.maxredirections,
|
||||
serv_list = cluster_nodes,
|
||||
connect_opts = connect_opts,
|
||||
})
|
||||
self.cluster = true
|
||||
|
||||
else
|
||||
local redis = redis_single:new()
|
||||
|
||||
if redis.set_timeouts then
|
||||
local send_timeout = tonumber(config.send_timeout, 10) or defaults.send_timeout
|
||||
local read_timeout = tonumber(config.read_timeout, 10) or defaults.read_timeout
|
||||
|
||||
if connect_timeout then
|
||||
if send_timeout and read_timeout then
|
||||
redis:set_timeouts(connect_timeout, send_timeout, read_timeout)
|
||||
else
|
||||
redis:set_timeout(connect_timeout)
|
||||
end
|
||||
end
|
||||
|
||||
elseif redis.set_timeout and connect_timeout then
|
||||
redis:set_timeout(connect_timeout)
|
||||
end
|
||||
|
||||
self.redis = redis
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.database = tonumber(config.database, 10) or defaults.database
|
||||
self.pool_timeout = tonumber(pool.timeout, 10) or defaults.pool.timeout
|
||||
self.connect_opts = connect_opts
|
||||
|
||||
local socket = config.socket or defaults.socket
|
||||
if socket and socket ~= "" then
|
||||
self.socket = socket
|
||||
else
|
||||
self.host = config.host or defaults.host
|
||||
self.port = config.port or defaults.port
|
||||
end
|
||||
end
|
||||
|
||||
return setmetatable(self, storage)
|
||||
end
|
||||
|
||||
function storage:connect()
|
||||
if self.cluster then
|
||||
return true -- cluster handles this on its own
|
||||
end
|
||||
|
||||
local ok, err
|
||||
if self.socket then
|
||||
ok, err = self.redis:connect(self.socket, self.connect_opts)
|
||||
else
|
||||
ok, err = self.redis:connect(self.host, self.port, self.connect_opts)
|
||||
end
|
||||
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
if self.password and self.redis:get_reused_times() == 0 then
|
||||
-- usernames are supported only on Redis 6+, so use new AUTH form only when absolutely necessary
|
||||
if self.username then
|
||||
ok, err = self.redis:auth(self.username, self.password)
|
||||
else
|
||||
ok, err = self.redis:auth(self.password)
|
||||
end
|
||||
if not ok then
|
||||
self.redis:close()
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
|
||||
if self.database ~= 0 then
|
||||
ok, err = self.redis:select(self.database)
|
||||
if not ok then
|
||||
self.redis:close()
|
||||
end
|
||||
end
|
||||
|
||||
return ok, err
|
||||
end
|
||||
|
||||
function storage:set_keepalive()
|
||||
if self.cluster then
|
||||
return true -- cluster handles this on its own
|
||||
end
|
||||
|
||||
return self.redis:set_keepalive(self.pool_timeout)
|
||||
end
|
||||
|
||||
function storage:key(id)
|
||||
return concat({ self.prefix, id }, ":" )
|
||||
end
|
||||
|
||||
function storage:lock(key)
|
||||
if not self.uselocking or self.locked then
|
||||
return true
|
||||
end
|
||||
|
||||
if not self.token then
|
||||
self.token = var.request_id
|
||||
end
|
||||
|
||||
local lock_key = concat({ key, "lock" }, "." )
|
||||
local lock_ttl = self.maxlockwait + 1
|
||||
local attempts = (1000 / self.spinlockwait) * self.maxlockwait
|
||||
local waittime = self.spinlockwait / 1000
|
||||
|
||||
for _ = 1, attempts do
|
||||
local ok = self.redis:set(lock_key, self.token, "EX", lock_ttl, "NX")
|
||||
if ok ~= null then
|
||||
self.locked = true
|
||||
return true
|
||||
end
|
||||
|
||||
sleep(waittime)
|
||||
end
|
||||
|
||||
return false, "unable to acquire a session lock"
|
||||
end
|
||||
|
||||
function storage:unlock(key)
|
||||
if not self.uselocking or not self.locked then
|
||||
return
|
||||
end
|
||||
|
||||
local lock_key = concat({ key, "lock" }, "." )
|
||||
|
||||
self.redis:eval(UNLOCK, 1, lock_key, self.token)
|
||||
self.locked = nil
|
||||
end
|
||||
|
||||
function storage:get(key)
|
||||
local data, err = self.redis:get(key)
|
||||
if not data then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
if data == null then
|
||||
return nil
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
function storage:set(key, data, lifetime)
|
||||
return self.redis:setex(key, lifetime, data)
|
||||
end
|
||||
|
||||
function storage:expire(key, lifetime)
|
||||
return self.redis:expire(key, lifetime)
|
||||
end
|
||||
|
||||
function storage:delete(key)
|
||||
return self.redis:del(key)
|
||||
end
|
||||
|
||||
function storage:open(id, keep_lock)
|
||||
local ok, err = self:connect()
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local key = self:key(id)
|
||||
|
||||
ok, err = self:lock(key)
|
||||
if not ok then
|
||||
self:set_keepalive()
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local data
|
||||
data, err = self:get(key)
|
||||
|
||||
if err or not data or not keep_lock then
|
||||
self:unlock(key)
|
||||
end
|
||||
self:set_keepalive()
|
||||
|
||||
return data, err
|
||||
end
|
||||
|
||||
function storage:start(id)
|
||||
if not self.uselocking or not self.locked then
|
||||
return true
|
||||
end
|
||||
|
||||
local ok, err = self:connect()
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
ok, err = self:lock(self:key(id))
|
||||
|
||||
self:set_keepalive()
|
||||
|
||||
return ok, err
|
||||
end
|
||||
|
||||
function storage:save(id, ttl, data, close)
|
||||
local ok, err = self:connect()
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local key = self:key(id)
|
||||
|
||||
ok, err = self:set(key, data, ttl)
|
||||
|
||||
if close then
|
||||
self:unlock(key)
|
||||
end
|
||||
|
||||
self:set_keepalive()
|
||||
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function storage:close(id)
|
||||
if not self.uselocking or not self.locked then
|
||||
return true
|
||||
end
|
||||
|
||||
local ok, err = self:connect()
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local key = self:key(id)
|
||||
|
||||
self:unlock(key)
|
||||
self:set_keepalive()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function storage:destroy(id)
|
||||
local ok, err = self:connect()
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local key = self:key(id)
|
||||
|
||||
ok, err = self:delete(key)
|
||||
|
||||
self:unlock(key)
|
||||
self:set_keepalive()
|
||||
|
||||
return ok, err
|
||||
end
|
||||
|
||||
function storage:ttl(id, ttl, close)
|
||||
local ok, err = self:connect()
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local key = self:key(id)
|
||||
|
||||
ok, err = self:expire(key, ttl)
|
||||
|
||||
if close then
|
||||
self:unlock(key)
|
||||
end
|
||||
|
||||
self:set_keepalive()
|
||||
|
||||
return ok, err
|
||||
end
|
||||
|
||||
return storage
|
||||
125
deps/src/lua-resty-session/lib/resty/session/storage/shm.lua
vendored
Normal file
125
deps/src/lua-resty-session/lib/resty/session/storage/shm.lua
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
local lock = require "resty.lock"
|
||||
|
||||
local setmetatable = setmetatable
|
||||
local tonumber = tonumber
|
||||
local concat = table.concat
|
||||
local var = ngx.var
|
||||
local shared = ngx.shared
|
||||
|
||||
local function enabled(value)
|
||||
if value == nil then return nil end
|
||||
return value == true or (value == "1" or value == "true" or value == "on")
|
||||
end
|
||||
|
||||
local function ifnil(value, default)
|
||||
if value == nil then
|
||||
return default
|
||||
end
|
||||
|
||||
return enabled(value)
|
||||
end
|
||||
|
||||
local defaults = {
|
||||
store = var.session_shm_store or "sessions",
|
||||
uselocking = enabled(var.session_shm_uselocking or true),
|
||||
lock = {
|
||||
exptime = tonumber(var.session_shm_lock_exptime, 10) or 30,
|
||||
timeout = tonumber(var.session_shm_lock_timeout, 10) or 5,
|
||||
step = tonumber(var.session_shm_lock_step, 10) or 0.001,
|
||||
ratio = tonumber(var.session_shm_lock_ratio, 10) or 2,
|
||||
max_step = tonumber(var.session_shm_lock_max_step, 10) or 0.5,
|
||||
}
|
||||
}
|
||||
|
||||
local storage = {}
|
||||
|
||||
storage.__index = storage
|
||||
|
||||
function storage.new(session)
|
||||
local config = session.shm or defaults
|
||||
local store = config.store or defaults.store
|
||||
local locking = ifnil(config.uselocking, defaults.uselocking)
|
||||
|
||||
local self = {
|
||||
store = shared[store],
|
||||
uselocking = locking,
|
||||
}
|
||||
|
||||
if locking then
|
||||
local lock_opts = config.lock or defaults.lock
|
||||
local opts = {
|
||||
exptime = tonumber(lock_opts.exptime, 10) or defaults.exptime,
|
||||
timeout = tonumber(lock_opts.timeout, 10) or defaults.timeout,
|
||||
step = tonumber(lock_opts.step, 10) or defaults.step,
|
||||
ratio = tonumber(lock_opts.ratio, 10) or defaults.ratio,
|
||||
max_step = tonumber(lock_opts.max_step, 10) or defaults.max_step,
|
||||
}
|
||||
self.lock = lock:new(store, opts)
|
||||
end
|
||||
|
||||
return setmetatable(self, storage)
|
||||
end
|
||||
|
||||
function storage:open(id, keep_lock)
|
||||
if self.uselocking then
|
||||
local ok, err = self.lock:lock(concat{ id, ".lock" })
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
|
||||
local data, err = self.store:get(id)
|
||||
|
||||
if self.uselocking and (err or not data or not keep_lock) then
|
||||
self.lock:unlock()
|
||||
end
|
||||
|
||||
return data, err
|
||||
end
|
||||
|
||||
function storage:start(id)
|
||||
if self.uselocking then
|
||||
return self.lock:lock(concat{ id, ".lock" })
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function storage:save(id, ttl, data, close)
|
||||
local ok, err = self.store:set(id, data, ttl)
|
||||
if close and self.uselocking then
|
||||
self.lock:unlock()
|
||||
end
|
||||
|
||||
return ok, err
|
||||
end
|
||||
|
||||
function storage:close()
|
||||
if self.uselocking then
|
||||
self.lock:unlock()
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function storage:destroy(id)
|
||||
self.store:delete(id)
|
||||
|
||||
if self.uselocking then
|
||||
self.lock:unlock()
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function storage:ttl(id, lifetime, close)
|
||||
local ok, err = self.store:expire(id, lifetime)
|
||||
|
||||
if close and self.uselocking then
|
||||
self.lock:unlock()
|
||||
end
|
||||
|
||||
return ok, err
|
||||
end
|
||||
|
||||
return storage
|
||||
232
deps/src/lua-resty-session/lib/resty/session/strategies/default.lua
vendored
Normal file
232
deps/src/lua-resty-session/lib/resty/session/strategies/default.lua
vendored
Normal file
@@ -0,0 +1,232 @@
|
||||
local type = type
|
||||
local concat = table.concat
|
||||
|
||||
local strategy = {}
|
||||
|
||||
function strategy.load(session, cookie, key, keep_lock)
|
||||
local storage = session.storage
|
||||
local id = cookie.id
|
||||
local id_encoded = session.encoder.encode(id)
|
||||
|
||||
local data, err, tag
|
||||
if storage.open then
|
||||
data, err = storage:open(id_encoded, keep_lock)
|
||||
if not data then
|
||||
return nil, err or "cookie data was not found"
|
||||
end
|
||||
|
||||
else
|
||||
data = cookie.data
|
||||
end
|
||||
|
||||
local expires = cookie.expires
|
||||
local usebefore = cookie.usebefore
|
||||
local hash = cookie.hash
|
||||
|
||||
if not key then
|
||||
key = concat{ id, expires, usebefore }
|
||||
end
|
||||
|
||||
local hkey = session.hmac(session.secret, key)
|
||||
|
||||
data, err, tag = session.cipher:decrypt(data, hkey, id, session.key, hash)
|
||||
if not data then
|
||||
if storage.close then
|
||||
storage:close(id_encoded)
|
||||
end
|
||||
|
||||
return nil, err or "unable to decrypt data"
|
||||
end
|
||||
|
||||
if tag then
|
||||
if tag ~= hash then
|
||||
if storage.close then
|
||||
storage:close(id_encoded)
|
||||
end
|
||||
|
||||
return nil, "cookie has invalid tag"
|
||||
end
|
||||
|
||||
else
|
||||
local input = concat{ key, data, session.key }
|
||||
if session.hmac(hkey, input) ~= hash then
|
||||
if storage.close then
|
||||
storage:close(id_encoded)
|
||||
end
|
||||
|
||||
return nil, "cookie has invalid signature"
|
||||
end
|
||||
end
|
||||
|
||||
data, err = session.compressor:decompress(data)
|
||||
if not data then
|
||||
if storage.close then
|
||||
storage:close(id_encoded)
|
||||
end
|
||||
|
||||
return nil, err or "unable to decompress data"
|
||||
end
|
||||
|
||||
data, err = session.serializer.deserialize(data)
|
||||
if not data then
|
||||
if storage.close then
|
||||
storage:close(id_encoded)
|
||||
end
|
||||
|
||||
return nil, err or "unable to deserialize data"
|
||||
end
|
||||
|
||||
session.id = id
|
||||
session.expires = expires
|
||||
session.usebefore = usebefore
|
||||
session.data = type(data) == "table" and data or {}
|
||||
session.present = true
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function strategy.open(session, cookie, keep_lock)
|
||||
return strategy.load(session, cookie, nil, keep_lock)
|
||||
end
|
||||
|
||||
function strategy.start(session)
|
||||
local storage = session.storage
|
||||
if not storage.start then
|
||||
return true
|
||||
end
|
||||
|
||||
local id_encoded = session.encoder.encode(session.id)
|
||||
|
||||
local ok, err = storage:start(id_encoded)
|
||||
if not ok then
|
||||
return nil, err or "unable to start session"
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function strategy.modify(session, action, close, key)
|
||||
local id = session.id
|
||||
local id_encoded = session.encoder.encode(id)
|
||||
local storage = session.storage
|
||||
local expires = session.expires
|
||||
local usebefore = session.usebefore
|
||||
local ttl = expires - session.now
|
||||
|
||||
if ttl <= 0 then
|
||||
if storage.close then
|
||||
storage:close(id_encoded)
|
||||
end
|
||||
|
||||
return nil, "session is already expired"
|
||||
end
|
||||
|
||||
if not key then
|
||||
key = concat{ id, expires, usebefore }
|
||||
end
|
||||
|
||||
local data, err = session.serializer.serialize(session.data)
|
||||
if not data then
|
||||
if close and storage.close then
|
||||
storage:close(id_encoded)
|
||||
end
|
||||
|
||||
return nil, err or "unable to serialize data"
|
||||
end
|
||||
|
||||
data, err = session.compressor:compress(data)
|
||||
if not data then
|
||||
if close and storage.close then
|
||||
storage:close(id_encoded)
|
||||
end
|
||||
|
||||
return nil, err or "unable to compress data"
|
||||
end
|
||||
|
||||
local hkey = session.hmac(session.secret, key)
|
||||
|
||||
local encrypted_data, tag
|
||||
encrypted_data, err, tag = session.cipher:encrypt(data, hkey, id, session.key)
|
||||
if not encrypted_data then
|
||||
if close and storage.close then
|
||||
storage:close(id_encoded)
|
||||
end
|
||||
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local hash
|
||||
if tag then
|
||||
hash = tag
|
||||
else
|
||||
-- it would be better to calculate signature from encrypted_data,
|
||||
-- but this is kept for backward compatibility
|
||||
hash = session.hmac(hkey, concat{ key, data, session.key })
|
||||
end
|
||||
|
||||
if action == "save" and storage.save then
|
||||
local ok
|
||||
ok, err = storage:save(id_encoded, ttl, encrypted_data, close)
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
elseif close and storage.close then
|
||||
local ok
|
||||
ok, err = storage:close(id_encoded)
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
|
||||
if usebefore then
|
||||
expires = expires .. ":" .. usebefore
|
||||
end
|
||||
|
||||
hash = session.encoder.encode(hash)
|
||||
|
||||
local cookie
|
||||
if storage.save then
|
||||
cookie = concat({ id_encoded, expires, hash }, "|")
|
||||
else
|
||||
local encoded_data = session.encoder.encode(encrypted_data)
|
||||
cookie = concat({ id_encoded, expires, encoded_data, hash }, "|")
|
||||
end
|
||||
|
||||
return cookie
|
||||
end
|
||||
|
||||
function strategy.touch(session, close)
|
||||
return strategy.modify(session, "touch", close)
|
||||
end
|
||||
|
||||
function strategy.save(session, close)
|
||||
return strategy.modify(session, "save", close)
|
||||
end
|
||||
|
||||
function strategy.destroy(session)
|
||||
local id = session.id
|
||||
if id then
|
||||
local storage = session.storage
|
||||
if storage.destroy then
|
||||
return storage:destroy(session.encoder.encode(id))
|
||||
elseif storage.close then
|
||||
return storage:close(session.encoder.encode(id))
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function strategy.close(session)
|
||||
local id = session.id
|
||||
if id then
|
||||
local storage = session.storage
|
||||
if storage.close then
|
||||
return storage:close(session.encoder.encode(id))
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return strategy
|
||||
43
deps/src/lua-resty-session/lib/resty/session/strategies/regenerate.lua
vendored
Normal file
43
deps/src/lua-resty-session/lib/resty/session/strategies/regenerate.lua
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
local default = require "resty.session.strategies.default"
|
||||
|
||||
local concat = table.concat
|
||||
|
||||
local strategy = {
|
||||
regenerate = true,
|
||||
start = default.start,
|
||||
destroy = default.destroy,
|
||||
close = default.close,
|
||||
}
|
||||
|
||||
local function key(source)
|
||||
if source.usebefore then
|
||||
return concat{ source.id, source.usebefore }
|
||||
end
|
||||
|
||||
return source.id
|
||||
end
|
||||
|
||||
function strategy.open(session, cookie, keep_lock)
|
||||
return default.load(session, cookie, key(cookie), keep_lock)
|
||||
end
|
||||
|
||||
function strategy.touch(session, close)
|
||||
return default.modify(session, "touch", close, key(session))
|
||||
end
|
||||
|
||||
function strategy.save(session, close)
|
||||
if session.present then
|
||||
local storage = session.storage
|
||||
if storage.ttl then
|
||||
storage:ttl(session.encoder.encode(session.id), session.cookie.discard, true)
|
||||
elseif storage.close then
|
||||
storage:close(session.encoder.encode(session.id))
|
||||
end
|
||||
|
||||
session.id = session:identifier()
|
||||
end
|
||||
|
||||
return default.modify(session, "save", close, key(session))
|
||||
end
|
||||
|
||||
return strategy
|
||||
39
deps/src/lua-resty-session/lua-resty-session-dev-1.rockspec
vendored
Normal file
39
deps/src/lua-resty-session/lua-resty-session-dev-1.rockspec
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
package = "lua-resty-session"
|
||||
version = "dev-1"
|
||||
source = {
|
||||
url = "git://github.com/bungle/lua-resty-session.git"
|
||||
}
|
||||
description = {
|
||||
summary = "Session Library for OpenResty – Flexible and Secure",
|
||||
detailed = "lua-resty-session is a secure, and flexible session library for OpenResty.",
|
||||
homepage = "https://github.com/bungle/lua-resty-session",
|
||||
maintainer = "Aapo Talvensaari <aapo.talvensaari@gmail.com>",
|
||||
license = "BSD"
|
||||
}
|
||||
dependencies = {
|
||||
"lua >= 5.1"
|
||||
}
|
||||
build = {
|
||||
type = "builtin",
|
||||
modules = {
|
||||
["resty.session"] = "lib/resty/session.lua",
|
||||
["resty.session.identifiers.random"] = "lib/resty/session/identifiers/random.lua",
|
||||
["resty.session.storage.shm"] = "lib/resty/session/storage/shm.lua",
|
||||
["resty.session.storage.dshm"] = "lib/resty/session/storage/dshm.lua",
|
||||
["resty.session.storage.redis"] = "lib/resty/session/storage/redis.lua",
|
||||
["resty.session.storage.cookie"] = "lib/resty/session/storage/cookie.lua",
|
||||
["resty.session.storage.memcache"] = "lib/resty/session/storage/memcache.lua",
|
||||
["resty.session.storage.memcached"] = "lib/resty/session/storage/memcached.lua",
|
||||
["resty.session.strategies.default"] = "lib/resty/session/strategies/default.lua",
|
||||
["resty.session.strategies.regenerate"] = "lib/resty/session/strategies/regenerate.lua",
|
||||
["resty.session.hmac.sha1"] = "lib/resty/session/hmac/sha1.lua",
|
||||
["resty.session.ciphers.aes"] = "lib/resty/session/ciphers/aes.lua",
|
||||
["resty.session.ciphers.none"] = "lib/resty/session/ciphers/none.lua",
|
||||
["resty.session.compressors.none"] = "lib/resty/session/compressors/none.lua",
|
||||
["resty.session.compressors.zlib"] = "lib/resty/session/compressors/zlib.lua",
|
||||
["resty.session.encoders.hex"] = "lib/resty/session/encoders/hex.lua",
|
||||
["resty.session.encoders.base16"] = "lib/resty/session/encoders/base16.lua",
|
||||
["resty.session.encoders.base64"] = "lib/resty/session/encoders/base64.lua",
|
||||
["resty.session.serializers.json"] = "lib/resty/session/serializers/json.lua"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user