I am attempting to write a class to store bans. I want to check if a given IP is banned and return #ip, #time, #reason etc.:
class BannedIP
attr_reader :ip, :time, :reason
def initialize(ip, time, reason)
#ip = ip
#time = time
#reason = reason
end
def banned?(ip)
# What do I use here?
end
end
I need help with the part # What do I use here? so that I can do something like:
if b = BannedIP.banned? '10.10.10.10'
I'm not sure returning ip when you already know ip makes sense but anyhoo...
You could use a custom hash class:
class BannedHash < Hash
def ban(ip, time, reason)
self[ip] = {time: time, reason: reason}
end
def banned?(ip)
if self.include?(ip)
self[ip]
else
"ip: #{ip} not found."
end
end
end
Usage:
def main
b = BannedHash.new
b.ban("10.10.10.10", Time.now, "Some reason")
puts b.banned?("10.10.10.10")
puts b.banned?("11.11.11.11")
end
Output:
{:time=>2015-04-27 21:18:39 +1200, :reason=>"Some reason"}
ip: 11.11.11.11 not found.
Bit of a waste to have a full class for this unless you are planning on putting more in it. If it's just this then track it with an array, it would be easier and cost you less memory.
class BannedIP
attr_accessor :ip, :time, :reason, :status
def initialize(ip)
#ip = ip
#time = Time.new
#reason = reason
#status = status.nil? ? false : true
end
def ban(reason)
#reason = reason
#time = Time.new
#status = true
end
def unban
#reason = ""
#time = Time.new
#status = false
end
def banned?
return #status
end
end
if __FILE__ == $0
puts "ban the bad guy at 10.0.0.1 because he was cheating"
a = BannedIP.new("10.0.0.1")
a.ban "he is a cheater!!"
puts "The status of 10.0.0.1 is " + a.status.to_s
end
$ ruby stack1.rb
ban the bad guy at 10.0.0.1 because he was cheating
The status of 10.0.0.1 is true
Install mysql2 and active record gems
gem install mysql2
gem install active_record
Then execute following code snapshot
require 'active_record'
require 'mysql2'
SOURCE_CREDNTIALS = {
:adapter => "mysql2",
:host => "localhost",
:username => "root",
:password => "password",
:database => "banned_db"
}
class Banned < ActiveRecord::Base
ActiveRecord::Base.establish_connection(SOURCE_CREDNTIALS)
#attr_accessor :id, :ip, :banned_at, :reason
def self.banned?(ip)
where(ip: ip).count > 0
end
end
Now you can use this simple class as
user_foo = Banned.create(ip: '10.10.10.10', banned_at: Time.now, reason: 'violated terms and conditions')
Banned.banned?('10.10.10.10')
BannedIP.banned? method would return true or false depending upon if particular ip is banned or not.
Related
Using the following:
Hanami cookbook websockets
IoT Saga - Part 3 - Websockets! Connecting LiteCable to Hanami
I've been able to add WebSockets to Hanami, however as this is for production code I want to add specs; but I can't find information on how to test WebSockets and Hanami using Rspec.
I've been able to find this for RoR but nothing non-Rails specific or Hanami Specific, I have asked on the Hanami Gitter but not gotten a response yet.
Is the TCR gem the only way? I would prefer something simpler but If I must how would I set it up for anycable-go via litecable.
How can I test WebSockets for Hanami using Rspec?
To get this working requires several moving parts, the first is the Socket simulator which simulates the receiving socket on the webserver:
Note: url_path should be customized to what works for your web socket specific endpoint
# frozen_string_literal: true
require 'puma'
require 'lite_cable/server'
require_relative 'sync_client'
class SocketSimulator
def initialize(x_site_id_header: nil)
#server_logs = []
#x_site_id_header = x_site_id_header
end
attr_accessor :server_logs
def client
return #client if #client
url_path = "/ws?connection_token=#{connection_token}"
#client = SyncClient.new("ws://127.0.0.1:3099#{url_path}", headers: headers, cookies: '')
end
def connection_token
#connection_token ||= SecureRandom.hex
end
def user
return #user if #user
email = "#{SecureRandom.hex}#mailinator.com"
password = SecureRandom.hex
#user = Fabricate.create :user, email: email, site_id: site_id, password: password
end
def start
#server = Puma::Server.new(
LiteCable::Server::Middleware.new(nil, connection_class: Api::Sockets::Connection),
Puma::Events.strings
).tap do |server|
server.add_tcp_listener '127.0.0.1', 3099
server.min_threads = 1
server.max_threads = 4
end
#server_thread = Thread.new { #server.run.join }
end
def teardown
#server&.stop(true)
#server_thread&.join
#server_logs.clear
end
def headers
{
'AUTHORIZATION' => "Bearer #{jwt}",
'X_HANAMI_DIRECT_BOOKINGS_SITE_ID' => #x_site_id_header || site_id
}
end
def site_id
#site_id ||= SecureRandom.hex
end
def jwt
#jwt ||= Interactors::Users::GenerateJwt.new(user, site_id).call.jwt
end
end
The next thing is the SyncClient which is a fake client you can use to actually connect to the simulated socket:
# frozen_string_literal: true
# Synchronous websocket client
# Copied and modified from https://github.com/palkan/litecable/blob/master/spec/support/sync_client.rb
class SyncClient
require 'websocket-client-simple'
require 'concurrent'
require 'socket'
WAIT_WHEN_EXPECTING_EVENT = 5
WAIT_WHEN_NOT_EXPECTING_EVENT = 0.5
attr_reader :pings
def initialize(url, headers: {}, cookies: '')
#messages = Queue.new
#closed = Concurrent::Event.new
#has_messages = Concurrent::Semaphore.new(0)
#pings = Concurrent::AtomicFixnum.new(0)
#open = Concurrent::Promise.new
#ws = set_up_web_socket(url, headers.merge('COOKIE' => cookies))
#open.wait!(WAIT_WHEN_EXPECTING_EVENT)
end
def ip
Socket.ip_address_list.detect(&:ipv4_private?).try(:ip_address)
end
def set_up_web_socket(url, headers)
WebSocket::Client::Simple.connect(
url,
headers: headers
) do |ws|
ws.on(:error, &method(:on_error))
ws.on(:open, &method(:on_open))
ws.on(:message, &method(:on_message))
ws.on(:close, &method(:on_close))
end
end
def on_error(event)
event = RuntimeError.new(event.message) unless event.is_a?(Exception)
if #open.pending?
#open.fail(event)
else
#messages << event
#has_messages.release
end
end
def on_open(_event = nil)
#open.set(true)
end
def on_message(event)
if event.type == :close
#closed.set
else
message = JSON.parse(event.data)
if message['type'] == 'ping'
#pings.increment
else
#messages << message
#has_messages.release
end
end
end
def on_close(_event = nil)
#closed.set
end
def read_message
#has_messages.try_acquire(1, WAIT_WHEN_EXPECTING_EVENT)
msg = #messages.pop(true)
raise msg if msg.is_a?(Exception)
msg
end
def read_messages(expected_size = 0)
list = []
loop do
list_is_smaller = list.size < expected_size ? WAIT_WHEN_EXPECTING_EVENT : WAIT_WHEN_NOT_EXPECTING_EVENT
break unless #has_messages.try_acquire(1, list_is_smaller)
msg = #messages.pop(true)
raise msg if msg.is_a?(Exception)
list << msg
end
list
end
def send_message(message)
#ws.send(JSON.generate(message))
end
def close
sleep WAIT_WHEN_NOT_EXPECTING_EVENT
raise "#{#messages.size} messages unprocessed" unless #messages.empty?
#ws.close
wait_for_close
end
def wait_for_close
#closed.wait(WAIT_WHEN_EXPECTING_EVENT)
end
def closed?
#closed.set?
end
end
The last part is a fake channel to test against:
# frozen_string_literal: true
class FakeChannel < Api::Sockets::ApplicationChannel
identifier :fake
def subscribed
logger.info "Can Reject? #{can_reject?}"
reject if can_reject?
logger.debug "Streaming from #{stream_location}"
stream_from stream_location
end
def unsubscribed
transmit message: 'Goodbye channel!'
end
def can_reject?
logger.info "PARAMS: #{params}"
params.fetch('value_to_check', 0) > 5
end
def foo
transmit('bar')
end
end
To use in specs:
# frozen_string_literal: true
require_relative '../../../websockets-test-utils/fake_channel'
require_relative '../../../websockets-test-utils/socket_simulator'
RSpec.describe Interactors::Channels::Broadcast, db_truncation: true do
subject(:interactor) { described_class.new(token: connection_token, loc: 'fake', message: message) }
let(:identifier) { { channel: 'fake' }.to_json }
let(:socket_simulator) { SocketSimulator.new }
let(:client) { socket_simulator.client }
let(:user) { socket_simulator.user }
let(:connection_token) { socket_simulator.connection_token }
let(:channel) { 'fake' }
let(:message) { 'woooooo' }
before do
socket_simulator.start
end
after do
socket_simulator.teardown
end
describe 'call' do
before do
client.send_message command: 'subscribe',
identifier: identifier
end
it 'broadcasts a message to the correct channel' do
expect(client.read_message).to eq('type' => 'welcome')
expect(client.read_message).to eq(
'identifier' => identifier,
'type' => 'confirm_subscription'
)
interactor.call
expect(client.read_message).to eq(
'identifier' => identifier,
'message' => message
)
end
context 'with other connection' do
let(:user2) { Fabricate.create :user }
let(:jwt) { Interactors::Users::GenerateJwt.new(user2, site_id).call.jwt }
let(:site_id) { socket_simulator.site_id }
let(:url_path) { "/ws?connection_token=#{SecureRandom.hex}" }
let(:client2) { SyncClient.new("ws://127.0.0.1:3099#{url_path}", headers: {}, cookies: '') }
before do
client2.send_message command: 'subscribe',
identifier: identifier
end
it "doesn't broadcast to connections that shouldn't get it" do
aggregate_failures 'broadcast!' do
expect(client2.read_message).to eq('type' => 'welcome')
expect(client2.read_message).to eq(
'identifier' => identifier,
'type' => 'confirm_subscription'
)
expect(client.read_message).to eq('type' => 'welcome')
expect(client.read_message).to eq(
'identifier' => identifier,
'type' => 'confirm_subscription'
)
interactor.call
sleep 1
expect(client.read_message).to eq(
'identifier' => identifier,
'message' => message
)
expect { client2.close }.not_to raise_exception
end
end
end
end
end
I have a program that attempts to generate open proxies, I will be using this program as a pentesting tool and have recently come across an error:
proxygen.rb:134:in `<=': comparison of Fixnum with nil failed (ArgumentError)
from proxygen.rb:134:in `check_for_amount_of_proxies'
from proxygen.rb:153:in `<main>'
What is happening is I have a variable #file_size and a variable #amount, the #amount variable is used to determine how many possible IP addresses are created and the #file_size is used to determine if the program has found the required amount of proxies and saved them to a file.
Source:
#!/usr/local/bin/env ruby
require 'colored'
require 'timeout'
require 'net/ping'
require 'proxies-scanner'
require 'etc'
LOGIN = Etc.getlogin
PATH = Dir.pwd
def fatal(input)
t = Time.now
puts "\n[[#{t.hour}:#{t.min}:#{t.sec} FATAL]]#{input}".red.bold
end
def notice(input)
t = Time.now
puts "\n[#{t.hour}:#{t.min}:#{t.sec} NOTICE]#{input}\n".blue.bold
end
def err(input)
t = Time.now
puts "[#{t.hour}:#{t.min}:#{t.sec} ERROR]#{input}".red.bold
end
def info(input)
t = Time.now
puts "[#{t.hour}:#{t.min}:#{t.sec} INFO]#{input}".green.bold
end
def success(input)
t= Time.now
puts "[#{t.hour}:#{t.min}:#{t.sec} [SUCCESS]#{input}".green.bold
end
def warn(input)
t = Time.now
puts "[#{t.hour}:#{t.min}:#{t.sec} WARNING]#{input}".yellow.bold
end
def self.windows?
return File.exist? "c:/WINDOWS" if RUBY_PLATFORM == 'java'
RUBY_PLATFORM =~ /mingw32/ || RUBY_PLATFORM =~ /mswin32/
end
def self.linux?
return File.exist? "/usr" if RUBY_PLATFORM == 'java'
RUBY_PLATFORM =~ /linux/
end
def self.os
return :linux if self.linux?
return :windows if self.windows?
nil
end
def check_os
notice("Hello #{LOGIN}, it appears that #{os.capitalize} is your OS, path has been switched to #{PATH}")
end
def check_file
if File.exist?("proxies.txt")
File.truncate("proxies.txt", 0)
notice("File exists in system, resuming process.")
else
notice("File proxies.txt created successfully.")
File.new("proxies.txt")
end
end
def choose_proxy_amount
print "Enter proxy amount: ".yellow.bold
#amount = gets.chomp.to_i
notice("Amount is measure in KB")
case #amount
when #amount >= 100
#file_size = 0..2154
when #amount <= 101
#file_size = 2166..21618
else
end
end
def create_possibles
notice("Attempting to ping generated IP addresses.")
ports = %w(80 443 1935 2222 3128 3130 7808 8080 8081 8085 8089
8090 8102 8104 8106 8118 8119 8123 8888 8898 9000
9090 9797 9999 10000 10052 10053 10059 10088 12345
18000 18001 18008 37564 40080 55336 59998
)
#amount.times do
#ip = Array.new(4){rand(256)}.join('.')
begin
Timeout::timeout(5) do
if Net::Ping::ICMP.new(#ip).ping?# == true
success("Possible proxies created for IP: #{#ip}")
File.open("proxies.txt", "a+") do |proxy|
ports.each { |port| proxy.puts("#{#ip}:#{port}") }
end
else
err("IP failed to ping: #{#ip}")
end
end
rescue Timeout::Error
warn("IP timed out: #{#ip}")
next
end
end
end
def check_for_amount_of_proxies
if File.size("proxies.txt") <= #file_size
notice("Proxies created, attempting connection")
system("proxies-scanner -f proxies.txt")
warn("Truncating file: proxies.txt")
else
notice("File doesn't contain enough proxies, restarting IP finding proccess.")
create_possibles
end
end
begin
check_file
check_os
choose_proxy_amount
create_possibles
check_for_amount_of_proxies
rescue RuntimeError => e
fatal("This program requires Adminstration access to run, please switch to admin terminal.")
end
So the program is failing when it tries to compare the size of the file to the variable #file_size. My question being is there a way to create this variable into a range?
The way you're assigning ranges is fine. Try assigning a range to a variable in IRB or Pry:
[3] (pry) main: 0> foo = 1..2
1..2
[4] (pry) main: 0> foo.class
Range < Object
You can't use <= #file_size if #file_size is a range:
5 <= 1..6
ArgumentError: bad value for range
or
5 <= (1..6)
ArgumentError: comparison of Fixnum with Range failed
You can use === instead:
(1..6) === 5
true
or:
#file_size === File.size("proxies.txt")
You can't reverse the order of the above. The range MUST be on the left:
5 === (1..6)
false
There's lots of pages explaining why.
I'm learning how to work with HTTParty and API and I'm having an issue with my code.
Users/admin/.rbenv/versions/2.0.0-p481/lib/ruby/2.0.0/uri/generic.rb:214:in `initialize': the scheme http does not accept registry part: :80 (or bad hostname?)
I've tried using debug_output STDOUT both as an argument to my method and after including HTTParty to have a clue but with no success. Nothing gets displayed:
require 'httparty'
class LolObserver
include HTTParty
default_timeout(1) #timeout after 1 second
attr_reader :api_key, :playerid
attr_accessor :region
def initialize(region,playerid,apikey)
#region = region_server(region)
#playerid = playerid
#api_key = apikey
end
def region_server(region)
case region
when "euw"
self.class.base_uri "https://euw.api.pvp.net"
self.region = "EUW1"
when "na"
self.class.base_uri "https://na.api.pvp.net"
self.region = "NA1"
end
end
def handle_timeouts
begin
yield
#Timeout::Error, is raised if a chunk of the response cannot be read within the read_timeout.
#Timeout::Error, is raised if a connection cannot be created within the open_timeout.
rescue Net::OpenTimeout, Net::ReadTimeout
#todo
end
end
def base_path
"/observer-mode/rest/consumer/getSpectatorGameInfo"
end
def current_game_info
handle_timeouts do
url = "#{ base_path }/#{region}/#{playerid}?api_key=#{api_key}"
puts '------------------------------'
puts url
HTTParty.get(url,:debug_output => $stdout)
end
end
end
I verified my URL which is fine so I'm lost as to where the problem is coming from.
I tested with a static base_uri and it doesn't change anything.
The odd thing is when I do:
HTTParty.get("https://euw.api.pvp.net/observer-mode/rest/consumer/getSpectatorGameInfo/EUW1/randomid?api_key=myapikey")
Everything is working fine and I'm getting a response.
HTTParty doesn't seem to like the way you set your base_uri.
Unless you need it to be like that just add another attr_reader called domain and it will work.
require 'httparty'
class LolObserver
include HTTParty
default_timeout(1) #timeout after 1 second
attr_reader :api_key, :playerid, :domain
attr_accessor :region
def initialize(region,playerid,apikey)
#region = region_server(region)
#playerid = playerid
#api_key = apikey
end
def region_server(region)
case region
when "euw"
#domain = "https://euw.api.pvp.net"
self.region = "EUW1"
when "na"
#domain = "https://na.api.pvp.net"
self.region = "NA1"
end
end
def handle_timeouts
begin
yield
#Timeout::Error, is raised if a chunk of the response cannot be read within the read_timeout.
#Timeout::Error, is raised if a connection cannot be created within the open_timeout.
rescue Net::OpenTimeout, Net::ReadTimeout
#todo
end
end
def base_path
"/observer-mode/rest/consumer/getSpectatorGameInfo"
end
def current_game_info
handle_timeouts do
url = "#{domain}/#{ base_path }/#{region}/#{playerid}?api_key=#{api_key}"
puts '------------------------------'
puts url
HTTParty.get(url,:debug_output => $stdout)
end
end
end
i'm having an issue configuring the sidekiq server, the process seems to be running in the foreground as soon as i refresh my page. /consumers/fetch i need to put it in the background permanently.
consumers_controller.rb
require 'kafka'
class ConsumersController < ApplicationController
def fetch
#consumer = Kafka::Consumer.new( { :host => ENV["host"],
:port => ENV["port"],
:topic => ENV["topic"]})
#consumer.loop do |message|
logger.info "-------------#{message.inspect}--------------"
logger.info "-------------#{message.first.payload.inspect}--------------"
unless message.blank?
ConsumerWorker.perform_async(message.first.payload)
end
end
end
end
consumer_worker.rb
class ConsumerWorker
include Sidekiq::Worker
def perform(message)
payload = message.first["payload"]
hash = JSON.parse(payload)
return #message = Message.new(hash) if hash["concern"] == 'order_create' or hash["concern"] == 'first_payment'
end
end
message.rb
class Message
attr_reader :bundle_id, :order_id, :order_number, :event
def initialize(message)
#payload = message["payload"]
#bundle_id = #payload["bundle_id"]
#order_id = #payload["order_id"]
#order_number = #payload["order_number"]
#event = message["concern"]
end
end
I think you need to move this block
#consumer.loop do |message|
end
inside your worker somehow, as I think the consumption is done after block execution.
I am trying to write an app as a gem using ActiveRecord without Rails.
My problem is how to migrate a database already deployed by a user who will not have rake, etc. I have just distributed a schema.rb file and created the db from that. But now I want to allow users to update to a new gem and migrate their db.
I've looked at ActiveRecord::Migrator, but can't figure out how to use it.
For example, how would I tell ActiveRecord::Migrator to run all migrations up from whatever is the current_migration?
Anyone have any suggestions for how to go about this or a good reference?
After going at this fresh this morning I came up with the following which is working well:
module Byr
module Db
class << self
attr_accessor :config
attr_accessor :adapter
attr_accessor :db_name
end
def self.create_sqlite(config)
require 'sqlite3'
config = config.merge('database' => File.join(Byr.db_dir, config['database']))
ActiveRecord::Base.establish_connection(config)
end
def self.create_pg(config)
require 'pg'
# Connect to the postgres db to create the db
ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres',
'schema_search_path' => 'public'))
begin
result = ActiveRecord::Base.connection.create_database(config['database'])
rescue PG::Error, ActiveRecord::StatementInvalid => e
unless e.message =~ /already exists/
raise
end
end
true
end
def self.mysql_creation_options(config)
#charset = ENV['CHARSET'] || 'utf8'
#collation = ENV['COLLATION'] || 'utf8_unicode_ci'
{:charset => (config['charset'] || #charset), :collation => (config['collation'] || #collation)}
end
def self.create_mysql(config)
require 'mysql2'
error_class = config['adapter'] =~ /mysql2/ ? Mysql2::Error : Mysql::Error
begin
ActiveRecord::Base.establish_connection(config.merge('database' => nil))
ActiveRecord::Base.connection.create_database(config['database'], mysql_creation_options(config))
ActiveRecord::Base.establish_connection(config)
rescue error_class => sqlerr
access_denied_error = 1045
if sqlerr.errno == access_denied_error
print "#{sqlerr.error}. \nPlease provide the root password for your mysql installation\n>"
root_password = $stdin.gets.strip
grant_statement = "GRANT ALL PRIVILEGES ON #{config['database']}.* " \
"TO '#{config['username']}'#'localhost' " \
"IDENTIFIED BY '#{config['password']}' WITH GRANT OPTION;"
ActiveRecord::Base.establish_connection(config.merge(
'database' => nil, 'username' => 'root', 'password' => root_password))
ActiveRecord::Base.connection.create_database(config['database'], mysql_creation_options(config))
ActiveRecord::Base.connection.execute grant_statement
ActiveRecord::Base.establish_connection(config)
else
Byr.warn sqlerr.error
Byr.warn "Couldn't create database for #{config.inspect}, charset: #{config['charset'] || #charset}, collation: #{config['collation'] || #collation}"
Byr.warn "(if you set the charset manually, make sure you have a matching collation)" if config['charset']
end
rescue ActiveRecord::StatementInvalid => e
ActiveRecord::Base.establish_connection(config)
end
end
def self.migrate
sys_migration_dir = File.join(Byr.install_dir, "db/migrate")
ActiveRecord::Migration.verbose = true
ActiveRecord::Migrator.migrate(sys_migration_dir)
end
def self.connected?
ActiveRecord::Base.connected? and
ActiveRecord::Base.connection_config[:adapter] == adapter
end
def self.disconnect
ActiveRecord::Base.connection_pool.disconnect!
end
# Really only for testing
def self.drop_db
ActiveRecord::Base.connection.drop_database(Byr.db_config)
end
end
end
Then, to initialize the db via the migrations:
module Byr
class << self
attr_accessor :install_dir
attr_accessor :db_dir
attr_accessor :config_dir
attr_accessor :config_file
attr_accessor :config
attr_accessor :db_config
attr_accessor :adapter
attr_accessor :database
def self.create_db
case db_config['adapter']
when /postgresql/
Byr::Db.create_pg(db_config)
when /sqlite/
Byr::Db.create_sqlite(db_config)
when /mysql/
Byr::Db.create_mysql(db_config)
else
raise ByrError "Your config.yml file specifies an unknown database adapter \'#{config['adapter']}\'"
end
end
def self.connect_db(reconnect = false)
unless reconnect
return true if Byr.connected?
end
ActiveRecord::Base.establish_connection(db_config)
end
def self.migrate
Byr::Db.migrate
end
def self.init(connect = true, adapter = nil)
adapter = canonicalize_adapter(adapter) if adapter
setup_db_config
if connect
create_db and connect_db and migrate
end
end
end
Some irrelevant parts of the code are omitted, but I hope this helps
someone else.
Much of the hard stuff comes from the rake tasks in rails.