-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: redis sandboxing #50
base: master
Are you sure you want to change the base?
Changes from all commits
df5317a
5bc4433
24dddff
9ea3c4a
4e046fe
8f50e77
905135b
e172c4c
bb64558
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# frozen_string_literal: true | ||
|
||
module SaferRailsConsole | ||
module Patches | ||
module Sandbox | ||
module RedisReadonly | ||
READ_COMMANDS = [ | ||
'hvals', 'bitcount', 'zscan', 'hget', 'smembers', 'hrandfield', 'zrevrange', 'bitpos', 'hlen', 'xlen', 'post', | ||
'zscore', 'dbsize', 'get', 'hstrlen', 'zrangebylex', 'scan', 'georadiusbymember_ro', 'zmscore', 'smismember', | ||
'zcount', 'lrange', 'stralgo', 'zrank', 'pttl', 'lpos', 'geopos', 'ttl', 'zrangebyscore', 'sdiff', 'llen', | ||
'sismember', 'zrevrangebyscore', 'zdiff', 'zrandmember', 'geodist', 'hexists', 'zrange', 'hmget', 'lindex', | ||
'zrevrangebylex', 'sunion', 'randomkey', 'zrevrank', 'xrange', 'xpending', 'hgetall', 'getrange', 'exists', | ||
'keys', 'georadius_ro', 'lolwut', 'hscan', 'object', 'zlexcount', 'type', 'geohash', 'touch', 'hkeys', | ||
'strlen', 'scard', 'substr', 'zinter', 'srandmember', 'mget', 'xinfo', 'geosearch', 'zunion', 'xread', | ||
'pfcount', 'xrevrange', 'sscan', 'memory', 'bitfield_ro', 'dump', 'host:', 'sinter', 'getbit', 'zcard' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is |
||
].freeze | ||
|
||
def self.raise_exception_on_write_command(command, service = ::Redis) | ||
unless READ_COMMANDS.include?(command.downcase.to_s) | ||
raise service.to_s.constantize::CommandError.new( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why |
||
"Write commands are not allowed in readonly mode: #{command}" | ||
) | ||
end | ||
end | ||
|
||
def self.handle_and_reraise_exception(error) | ||
if error.message.include?('Write commands are not allowed') | ||
puts SaferRailsConsole::Colors.color_text( # rubocop:disable Rails/Output | ||
'An operation could not be completed due to read-only mode.', | ||
SaferRailsConsole::Colors::RED | ||
) | ||
end | ||
|
||
raise error | ||
end | ||
|
||
module RedisPatch | ||
def process(commands) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this work for pipelined/multi commands? I think this may only catch this first command being executed. |
||
begin | ||
command = commands.flatten.first | ||
SaferRailsConsole::Patches::Sandbox::RedisReadonly.raise_exception_on_write_command(command) | ||
rescue Redis::CommandError => e | ||
SaferRailsConsole::Patches::Sandbox::RedisReadonly.handle_and_reraise_exception(e) | ||
end | ||
super | ||
end | ||
end | ||
|
||
module RedisClientPatch | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
def call(commands, redis_config) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Likewise I don't think this covers pipelines or multis? |
||
command = commands.first | ||
begin | ||
SaferRailsConsole::Patches::Sandbox::RedisReadonly.raise_exception_on_write_command(command, | ||
::RedisClient) | ||
rescue RedisClient::CommandError => e | ||
SaferRailsConsole::Patches::Sandbox::RedisReadonly.handle_and_reraise_exception(e) | ||
end | ||
super | ||
end | ||
end | ||
|
||
::Redis::Client.prepend(RedisPatch) if defined?(::Redis::Client) | ||
::RedisClient.register(RedisClientPatch) if defined?(::RedisClient) | ||
end | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm vaguely worried about this list falling out of date as new commands are added, but I think it's fine since we're whitelisting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also a nit, can we alphabetize these?