unibanner 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a987a90282931e2839767ae60f520bcca07c7635f3e66f2481c4e2ce8bae9f59
4
+ data.tar.gz: 7804309c159b11547855b6cbc3e1083b05c0e6ca1a2914344079c58c0d99f176
5
+ SHA512:
6
+ metadata.gz: d6e62892ca52da8cca98641430088d06233fc6b9e4739f6dfbff3686a9c11ef9e4404dea3f759f72fefc7be01cfc6a34a1eddf09255086c6a04e60fb7cd467a2
7
+ data.tar.gz: 7d32bb8ce10aa2351bf336407030e2c9734624eba46aac6f2bca675b36cb7b6d0ef884cca002d2783ba96f3d6916abff4c3093745ba0aaaf7571de36060e1c57
data/.bundle/config ADDED
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_PATH: "vendor/bundle"
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ vendor/
2
+ .project
3
+ .vscode/
4
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,57 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ unibanner (0.0.0)
5
+ irc_socket (~> 1.0, >= 1)
6
+ logging (~> 2.2.2)
7
+ paint (~> 2.0.1)
8
+ parseconfig (~> 1.0.8)
9
+ pry
10
+ unirest (~> 1.1.2)
11
+
12
+ GEM
13
+ remote: https://rubygems.org/
14
+ specs:
15
+ addressable (2.3.8)
16
+ ansi (1.5.0)
17
+ builder (3.2.3)
18
+ coderay (1.1.2)
19
+ irc_socket (1.0.7)
20
+ json (1.8.6)
21
+ little-plugger (1.1.4)
22
+ logging (2.2.2)
23
+ little-plugger (~> 1.1)
24
+ multi_json (~> 1.10)
25
+ method_source (0.9.1)
26
+ mime-types (1.25.1)
27
+ minitest (5.11.3)
28
+ minitest-reporters (1.3.5)
29
+ ansi
30
+ builder
31
+ minitest (>= 5.0)
32
+ ruby-progressbar
33
+ multi_json (1.13.1)
34
+ paint (2.0.1)
35
+ parseconfig (1.0.8)
36
+ pry (0.12.0)
37
+ coderay (~> 1.1.0)
38
+ method_source (~> 0.9.0)
39
+ rest-client (1.6.9)
40
+ mime-types (~> 1.16)
41
+ ruby-progressbar (1.10.0)
42
+ unirest (1.1.2)
43
+ addressable (~> 2.3.5)
44
+ json (~> 1.8.1)
45
+ rest-client (~> 1.6.7)
46
+
47
+ PLATFORMS
48
+ ruby
49
+
50
+ DEPENDENCIES
51
+ bundler (~> 1.16)
52
+ minitest (~> 5)
53
+ minitest-reporters (~> 1.1)
54
+ unibanner!
55
+
56
+ BUNDLED WITH
57
+ 1.16.4
data/bin/unibanner ADDED
@@ -0,0 +1,5 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'unibanner'
4
+ Unibanner::Bots.find_bots
5
+ Unibanner::Bots.start
@@ -0,0 +1,163 @@
1
+ require "logging"
2
+ require "irc_socket"
3
+ require "yaml"
4
+ require "unibanner/logger"
5
+
6
+ module Unibanner
7
+ # class containing all the bot instances and methods to act on them.
8
+ class Bots
9
+ @@bots = {}
10
+ @@threads = []
11
+ Unibanner::Logger.new(self)
12
+ @@log = Unibanner::Logger[self]
13
+
14
+ def initialize
15
+ @log = @@log
16
+ end
17
+
18
+ # Find all bots existing in configuration
19
+ def self.find_bots
20
+ cfg = YAML::load_file(Pathname(Dir.home).join(".unibanner").join("config"))
21
+ cfg["networks"].each do |network, hsh|
22
+ @@log.debug "bot = Unibanner::Bot.new(#{network}, #{hsh})"
23
+ bot = Unibanner::Bot.new(network, hsh)
24
+ @@log.debug "Unibanner::Bots.add_bot(#{bot})"
25
+ Unibanner::Bots.add_bot(bot)
26
+ @@log.debug "Unibanner::Bot.find_bots ... done."
27
+ end
28
+ end
29
+
30
+ # Add a bot into the Bots list
31
+ # @param [Unibanner::Bot] bot Unibanner::Bot object
32
+ def self.add_bot(bot)
33
+ @@bots[bot.network] = bot
34
+ end
35
+
36
+ # return list of bots
37
+ # @return [Array] bots list
38
+ def self.bots
39
+ @@bots
40
+ end
41
+
42
+ # Start all bots found via Bots#find_bots
43
+ def self.start
44
+ @@bots.each do |network, bot|
45
+ thr = Thread.new do
46
+ Thread.current.name = "#{bot.nick}@#{network}[#{bot.server}:#{bot.ssl == true ? '+' : ''}#{bot.port}]"
47
+ bot.start
48
+ end
49
+ @@threads << thr
50
+ @@threads.each(&:join)
51
+ end
52
+ end
53
+
54
+ # Cause all bots to die/quit
55
+ # @overload self.die(msg)
56
+ # Quits all bots with 'msg'
57
+ # and all threads are exited.
58
+ # @param [String] msg quit msg to use
59
+ # @overload self.die(msg, threads)
60
+ # Quits all bots with 'msg'
61
+ # and threads determines if threads are killed
62
+ # @param [String] msg quit msg to use
63
+ # @param [Boolean] threads whether to kill/exit threads
64
+ def self.die(msg, threads = true)
65
+ @@bots.each do |network, bot|
66
+ @@log.info "Quitting off #{network}."
67
+ bot.quit(msg)
68
+ end
69
+ if threads
70
+ @@threads.each do |thr|
71
+ @@log.info "Exiting from '#{thr.name}' thread."
72
+ thr.exit
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ class Bot
79
+ attr_accessor :irc, :sock
80
+ attr_reader :server, :port, :ssl, :network, :local_host, :nick, :geckos, :prefix, :oper_name
81
+ attr :log, :log_level
82
+
83
+ # Create a new bot
84
+ # @param [String] network The network name
85
+ # @param [Hash] hsh hash full of network options
86
+ def initialize(network, hsh)
87
+ @network = group
88
+ @server = hsh["server"] # network::server: irc.server.tld
89
+ @ssl = hsh["ssl"] # network::ssl: true/false
90
+ @port = hsh["port"] # network::port: 0000
91
+ @local_host = hsh["local_host"] # network::local_host: 0.0.0.0
92
+ @nick = hsh["nick"] # network::nick: nickname
93
+ @geckos = hsh["geckos"] # network::geckos: Real Name
94
+ @prefix = hsh["prefix"] # network::prefix: !
95
+ @oper_name = hsh["oper_name"] # network::oper_name: opername
96
+ @oper_pass = hsh["oper_pass"] # network::oper_pass: PASSWORD
97
+ @channels = hsh["channels"] # network::channels: [channel1,channel2]
98
+
99
+ Unibanner::Logger.new(self)
100
+ @log = Unibanner::Logger[self]
101
+ @log_level = hsh["log_level"]
102
+ @log.level = @log_level
103
+ @irc = IRCSocket.new(@server, @port, @ssl)
104
+ end
105
+
106
+ # Allow Bot.quit(msg) to actually cause the irc connection to /quit
107
+ # @param [String] msg Quit msg to use
108
+ def quit(msg)
109
+ @irc.quit(msg)
110
+ end
111
+
112
+ # Start the IRC connection
113
+ # @return [nil]
114
+ def start
115
+ @irc.connect
116
+ if @irc.connected?
117
+ @irc.nick "#{@nick}"
118
+ @irc.user "#{@nick}", 0, "*", "#{@geckos}"
119
+ while line = irc.read
120
+ @log.incoming line
121
+ # Join Channels after MOTD
122
+ if line.split[1] == "376"
123
+ Thread.new {
124
+ @irc.oper @oper_name, @oper_pass
125
+ @channels.each do |channel|
126
+ @irc.join channel
127
+ end
128
+ }
129
+ end
130
+ # 0 1 2 ------------------3-------------------
131
+ # :kojo.electrocode.net 340 unibanner :ephemer0l_=+~ephemer0l_@196.27.72.156
132
+
133
+ if line.split[1] == "340"
134
+ user_ip = line.split[3].gsub(/:.*@(.*)/, '\1')
135
+ @log.info "Got #{user_ip} back from /USERIP. Submitting to blacklist."
136
+ #reply = SendToBlacklist(user_ip)
137
+ @log.debug "send2BL(#{user_ip}) returned '#{reply}'"
138
+ #ircZLine(user_ip)
139
+ end
140
+ if line.split[1] == '433'
141
+ @log.error "#{self.network}: 433, Nickname in use, can't connect"
142
+ ::Unibanner::Bots.die("Nickname in use, Can't connect")
143
+ end
144
+ # unicode characters used by the spammers
145
+ # spam_pattern = /(\uFE13|\u04BB|\u0501|\u0D20|\u222A|\u217E|\u1EFF){1,}/
146
+ spam_pattern = Regexp.new('(\ufe68|\u205f|\u0422|\u2009|\u04bb|\u1952|\u217c|\u2004|\u217f|\u1d20|\u03bf|\u0456|\u217d|\u2c9f|\u2024|\u0435|\uff03|\uff0f|\u03f3|\ufe57|\u2216|\u2170|\u1959|\u13df|\u0251|\u222a|\u0441|\u0430|\u2001|\u200a|\u217e|\u0443|\u2005|\u2002|\u0455|\u2000|\u2215|\u2044|\u03f2|\u043e|\u0d20|\u0261|\u1971|\u0501|\u2007|\u0392|\uff0e|\u13a1|\u0458|\u202f|\ufe55|\u15b4|\u1d21|\u2006|\u2cad|\u0440|\u2574|\u16ec|\u13da|\u13a2)')
147
+ # message pattern
148
+ nick_pattern = Regexp.new(':(?<nick>.*)!(?<user>.+)\@(?<host>\S+) PRIVMSG (?<channel>\#\S+) :(?<msg>.*)')
149
+ # Run a /USERIP on the nick that matched the spam text
150
+ if line =~ nick_pattern
151
+ @log.info "matched on nick pattern"
152
+ irc_msg = Regexp.last_match
153
+ if irc_msg["msg"] =~ spam_pattern
154
+ @log.info "matched on spam pattern"
155
+ @irc.userip(irc_msg["nick"])
156
+ end
157
+ end
158
+ end
159
+ end
160
+ return nil
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,22 @@
1
+ module Unibanner
2
+ # A group of functions to help with unibanner
3
+ # @attr [String] key DNSBL.im key file contents
4
+ class Functions
5
+ # Send an IP to the blacklist
6
+ # A bit longer description.
7
+ #
8
+ # @param [String] ip IP sending to blacklist
9
+ # @returns [True,False]
10
+ def send2BL(ip)
11
+ url = 'https://api.dnsbl.im/import'
12
+ payload = {
13
+ key: File.open('/home/ken/.dnsblim-key', 'r').read.chomp!,
14
+ addresses: [
15
+ {type: '5,6', ip: ip, reason: 'fngate and/or unicode spam'}
16
+ ]
17
+ }
18
+ r = Unirest.post(url, parameters: payload.to_json)
19
+ r.body
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,63 @@
1
+ require "logging"
2
+ require 'paint'
3
+ module Logging
4
+ class Logger
5
+
6
+ def incoming?( ); true; end
7
+ def incoming( data = nil )
8
+ data = yield if block_given?
9
+ log_event(::Logging::LogEvent.new(@name, 1, " #{Paint['->', 'green']} #{data}", @caller_tracing))
10
+ true
11
+ end
12
+ def outgoing?( ); true; end
13
+ def outgoing( data = nil )
14
+ data = yield if block_given?
15
+ log_event(::Logging::LogEvent.new(@name, 1, " #{Paint['<-', 'red']} #{data}", @caller_tracing))
16
+ true
17
+ end
18
+ end
19
+ end
20
+ Logging.color_scheme("bright",
21
+ :levels => {
22
+ :info => :green,
23
+ :warn => :yellow,
24
+ :error => :red,
25
+ :fatal => [:white, :on_red],
26
+ },
27
+ :date => :blue,
28
+ :logger => :cyan,
29
+ :message => :white)
30
+
31
+ Logging.appenders.stdout(
32
+ "stdout",
33
+ :layout => Logging.layouts.pattern(
34
+ :pattern => '[%d] %-5l %c: %m\n',
35
+ :color_scheme => "bright",
36
+ ),
37
+ )
38
+ Logging.logger.root.appenders = Logging.appenders.stdout
39
+ Logging.logger.root.level = :info
40
+
41
+ module Unibanner
42
+ LOGGER = Logging.logger[self]
43
+ class Logger
44
+ @@loggers = {}
45
+ @@loggers['Unibanner'] = Logging.logger['Unibanner']
46
+ @@loggers[self] = Logging.logger[self]
47
+ @@instance = Logging::Repository.instance
48
+
49
+ def initialize(name)
50
+ @@loggers[name] = Logging.logger[name]
51
+ end
52
+
53
+ def update
54
+ @@instance = Logging::Repository.instance
55
+ end
56
+ def loggers
57
+ @@loggers
58
+ end
59
+ def self.[](key)
60
+ @@loggers[key]
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,3 @@
1
+ module Unibanner
2
+ VERSION = '0.0.1'
3
+ end
data/lib/unibanner.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'unibanner/bot_class'
2
+
3
+ # vim: ts=2 sw=2
data/unibanner.gemspec ADDED
@@ -0,0 +1,48 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'unibanner/version'
4
+ Gem::Specification.new do |s|
5
+ s.name = 'unibanner'
6
+ s.version = Unibanner::VERSION
7
+ s.authors = ['Ken Spencer']
8
+ s.email = 'me@iotaspencer.me'
9
+ s.summary = 'A simpleish bot made to ban and blacklist unicode spamming bots.'
10
+ s.description = 'A simple bot made to ban and blacklist unicode spamming bots on IRC. Use only in channels where such unicode is not commonplace.'
11
+ s.homepage = 'https://iotaspencer.me/projects/unibanner'
12
+ s.license = 'MIT'
13
+
14
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
15
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
16
+ if s.respond_to?(:metadata)
17
+ s.metadata = {
18
+ 'github_repo' => 'https://git.lasershark.army/IotaSpencer/unibanner',
19
+ 'bug_tracker_uri' => 'https://git.lasershark.army/IotaSpencer/unibanner/issues',
20
+ # 'documentation_uri' => 'https://rubydoc.info/gems/unibanner',
21
+ 'homepage_uri' => 'https://iotaspencer.me/projects/unibanner',
22
+ 'source_code_uri' => 'https://git.lasershark.army/IotaSpencer/unibanner',
23
+ 'wiki_uri' => 'https://git.lasershark.army/IotaSpencer/unibanner/wiki'
24
+ }
25
+ else
26
+ raise 'RubyGems 2.0 or newer is required to protect against ' \
27
+ 'public gem pushes.'
28
+ end
29
+
30
+ s.files = `git ls-files -z`.split("\x0").reject do |f|
31
+ f.match(%r{^(test)/})
32
+ end
33
+ s.required_ruby_version = '~> 2'
34
+ s.bindir = 'bin'
35
+ s.executables << 'unibanner'
36
+ s.require_paths = ['lib']
37
+
38
+ s.add_runtime_dependency 'irc_socket', '~> 1.0', '>= 1'
39
+ s.add_runtime_dependency 'logging', '~> 2.2.2'
40
+ s.add_runtime_dependency 'paint', '~> 2.0.1'
41
+ s.add_runtime_dependency 'parseconfig', '~> 1.0.8'
42
+ s.add_runtime_dependency 'pry'
43
+ s.add_runtime_dependency 'unirest', '~> 1.1.2'
44
+ s.add_development_dependency 'bundler', '~> 1.16'
45
+ s.add_development_dependency 'minitest', '~> 5'
46
+ s.add_development_dependency 'minitest-reporters', '~> 1.1'
47
+
48
+ end
metadata ADDED
@@ -0,0 +1,193 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: unibanner
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ken Spencer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-11-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: irc_socket
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: '1'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '1'
33
+ - !ruby/object:Gem::Dependency
34
+ name: logging
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 2.2.2
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: 2.2.2
47
+ - !ruby/object:Gem::Dependency
48
+ name: paint
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: 2.0.1
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: 2.0.1
61
+ - !ruby/object:Gem::Dependency
62
+ name: parseconfig
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: 1.0.8
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: 1.0.8
75
+ - !ruby/object:Gem::Dependency
76
+ name: pry
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: unirest
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: 1.1.2
96
+ type: :runtime
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: 1.1.2
103
+ - !ruby/object:Gem::Dependency
104
+ name: bundler
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '1.16'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '1.16'
117
+ - !ruby/object:Gem::Dependency
118
+ name: minitest
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '5'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '5'
131
+ - !ruby/object:Gem::Dependency
132
+ name: minitest-reporters
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '1.1'
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '1.1'
145
+ description: A simple bot made to ban and blacklist unicode spamming bots on IRC.
146
+ Use only in channels where such unicode is not commonplace.
147
+ email: me@iotaspencer.me
148
+ executables:
149
+ - unibanner
150
+ extensions: []
151
+ extra_rdoc_files: []
152
+ files:
153
+ - ".bundle/config"
154
+ - ".gitignore"
155
+ - Gemfile
156
+ - Gemfile.lock
157
+ - bin/unibanner
158
+ - lib/unibanner.rb
159
+ - lib/unibanner/bot_class.rb
160
+ - lib/unibanner/functions.rb
161
+ - lib/unibanner/logger.rb
162
+ - lib/unibanner/version.rb
163
+ - unibanner.gemspec
164
+ homepage: https://iotaspencer.me/projects/unibanner
165
+ licenses:
166
+ - MIT
167
+ metadata:
168
+ github_repo: https://git.lasershark.army/IotaSpencer/unibanner
169
+ bug_tracker_uri: https://git.lasershark.army/IotaSpencer/unibanner/issues
170
+ homepage_uri: https://iotaspencer.me/projects/unibanner
171
+ source_code_uri: https://git.lasershark.army/IotaSpencer/unibanner
172
+ wiki_uri: https://git.lasershark.army/IotaSpencer/unibanner/wiki
173
+ post_install_message:
174
+ rdoc_options: []
175
+ require_paths:
176
+ - lib
177
+ required_ruby_version: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - "~>"
180
+ - !ruby/object:Gem::Version
181
+ version: '2'
182
+ required_rubygems_version: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
187
+ requirements: []
188
+ rubyforge_project:
189
+ rubygems_version: 2.7.6
190
+ signing_key:
191
+ specification_version: 4
192
+ summary: A simpleish bot made to ban and blacklist unicode spamming bots.
193
+ test_files: []