blur 1.8.6 → 2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +0 -11
- data/executables/blur +62 -0
- data/library/blur.rb +37 -12
- data/library/blur/callbacks.rb +59 -0
- data/library/blur/channel.rb +75 -0
- data/library/blur/client.rb +122 -91
- data/library/blur/enhancements.rb +1 -3
- data/library/blur/handling.rb +117 -125
- data/library/blur/logging.rb +41 -0
- data/library/blur/network.rb +54 -36
- data/library/blur/network/connection.rb +2 -2
- data/library/blur/script.rb +124 -117
- data/library/blur/script_cache.rb +43 -0
- data/library/blur/user.rb +105 -0
- data/library/blur/version.rb +1 -1
- metadata +17 -21
- data/library/blur/encryption.rb +0 -17
- data/library/blur/encryption/base64.rb +0 -71
- data/library/blur/encryption/fish.rb +0 -80
- data/library/blur/evaluable.rb +0 -13
- data/library/blur/extension.rb +0 -42
- data/library/blur/network/channel.rb +0 -91
- data/library/blur/network/command.rb +0 -83
- data/library/blur/network/user.rb +0 -106
- data/library/blur/script/cache.rb +0 -77
- data/library/blur/script/commands.rb +0 -77
- data/library/blur/script/dsl.rb +0 -52
data/library/blur/encryption.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Blur
|
4
|
-
# The +Encryption+ module extends the communication-functionality of
|
5
|
-
# the client. It is intended to enable helpers but also core functionality
|
6
|
-
# that encrypts the incoming and outgoing data of Blur.
|
7
|
-
#
|
8
|
-
# Encryption modules are not loaded into the VM until it's required.
|
9
|
-
module Encryption
|
10
|
-
# Indicates that user-input (a channel user message, e.g.) is in invalid
|
11
|
-
# format to a certain encryption algorithm.
|
12
|
-
class BadInputError < StandardError; end
|
13
|
-
|
14
|
-
autoload :FiSH, "blur/encryption/fish"
|
15
|
-
autoload :Base64, "blur/encryption/base64"
|
16
|
-
end
|
17
|
-
end
|
@@ -1,71 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Blur
|
4
|
-
module Encryption
|
5
|
-
# The +Encryption::Base64+ module differs from the original Base64
|
6
|
-
# implementation. I'm not sure how exactly, perhaps the charset?
|
7
|
-
#
|
8
|
-
# I originally found the Ruby implementation of FiSH on a website where
|
9
|
-
# it was graciously submitted by an anonymous user, since then I've
|
10
|
-
# implemented it in a weechat script, and now I've refactored it for use in
|
11
|
-
# Blur.
|
12
|
-
#
|
13
|
-
# @see http://maero.dk/pub/sources/weechat/ruby/autoload/fish.rb
|
14
|
-
module Base64
|
15
|
-
# The difference I suspect between the original Base64 implementation
|
16
|
-
# and the one used in FiSH.
|
17
|
-
Charset = "./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
18
|
-
|
19
|
-
# Decode a base64-encoded string.
|
20
|
-
#
|
21
|
-
# @return [String] Base64-decoded string.
|
22
|
-
def self.decode string
|
23
|
-
unless string.length % 12 == 0
|
24
|
-
raise BadInputError, "input has to be a multiple of 12 characters."
|
25
|
-
end
|
26
|
-
|
27
|
-
String.new.tap do |buffer|
|
28
|
-
j = -1
|
29
|
-
|
30
|
-
while j < string.length - 1
|
31
|
-
right, left = 0, 0
|
32
|
-
|
33
|
-
6.times{|i| right |= Charset.index(string[j += 1]) << (i * 6) }
|
34
|
-
6.times{|i| left |= Charset.index(string[j += 1]) << (i * 6) }
|
35
|
-
|
36
|
-
4.times do |i|
|
37
|
-
buffer << ((left & (0xFF << ((3 - i) * 8))) >> ((3 - i) * 8)).chr
|
38
|
-
end
|
39
|
-
|
40
|
-
4.times do |i|
|
41
|
-
buffer << ((right & (0xFF << ((3 - i) * 8))) >> ((3 - i) * 8)).chr
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# Encode a string-cipher.
|
48
|
-
#
|
49
|
-
# @return [String] Base64-encoded string.
|
50
|
-
def self.encode string
|
51
|
-
unless string.length % 8 == 0
|
52
|
-
raise BadInputError, "input has to be a multiple of 8 characters."
|
53
|
-
end
|
54
|
-
|
55
|
-
left = 0
|
56
|
-
right = 0
|
57
|
-
decimals = [24, 16, 8, 0]
|
58
|
-
|
59
|
-
String.new.tap do |buffer|
|
60
|
-
string.each_block do |block|
|
61
|
-
4.times{|i| left += (block[i].ord << decimals[i]) }
|
62
|
-
4.times{|i| right += (block[i+4].ord << decimals[i]) }
|
63
|
-
|
64
|
-
6.times{|i| buffer << Charset[right & 0x3F].chr; right = right >> 6 }
|
65
|
-
6.times{|i| buffer << Charset[left & 0x3F].chr; left = left >> 6 }
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
@@ -1,80 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'crypt/blowfish'
|
4
|
-
|
5
|
-
module Blur
|
6
|
-
module Encryption
|
7
|
-
# The +FiSH+ algorithm is a combination of Base64 encoding
|
8
|
-
# and the blowfish encryption.
|
9
|
-
#
|
10
|
-
# Shared text messages are prepended by "++OK+", an older implementation
|
11
|
-
# prepends it with "+mcps+" - Blur drops support for that implementation.
|
12
|
-
#
|
13
|
-
# There's multiple client-implementations available on the official FiSH
|
14
|
-
# homepage.
|
15
|
-
#
|
16
|
-
# == DH1080 Key exchange
|
17
|
-
# The newer FiSH implementation introduces a 1080bit Diffie-Hellman
|
18
|
-
# key-exchange mechanism.
|
19
|
-
#
|
20
|
-
# Blur does currently not support key exchanges.
|
21
|
-
class FiSH
|
22
|
-
# The standard FiSH block-size.
|
23
|
-
BlockSize = 8
|
24
|
-
|
25
|
-
# @return [String] the blowfish salt-key.
|
26
|
-
attr_accessor :keyphrase
|
27
|
-
|
28
|
-
# Change the keyphrase and instantiate a new blowfish object.
|
29
|
-
def keyphrase= keyphrase
|
30
|
-
@keyphrase = keyphrase
|
31
|
-
@blowfish = Crypt::Blowfish.new @keyphrase
|
32
|
-
end
|
33
|
-
|
34
|
-
# Instantiate a new fish-encryption object.
|
35
|
-
def initialize keyphrase
|
36
|
-
@keyphrase = keyphrase
|
37
|
-
@blowfish = Crypt::Blowfish.new keyphrase
|
38
|
-
end
|
39
|
-
|
40
|
-
# Encrypt an input string using the keyphrase stored in the +@blowfish+
|
41
|
-
# object.
|
42
|
-
#
|
43
|
-
# @return [String] the encrypted string.
|
44
|
-
def encrypt string
|
45
|
-
String.new.tap do |buffer|
|
46
|
-
nullpad(string).each_block do |block|
|
47
|
-
chunk = @blowfish.encrypt_block block
|
48
|
-
buffer.concat Base64.encode chunk
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
# Decrypt an input string using the keyphrase stored in the +@blowfish+
|
54
|
-
# object.
|
55
|
-
#
|
56
|
-
# @return [String] the decrypted string.
|
57
|
-
def decrypt string
|
58
|
-
unless string.length % 12 == 0
|
59
|
-
raise BadInputError, "input has to be a multiple of 12 characters."
|
60
|
-
end
|
61
|
-
|
62
|
-
String.new.tap do |buffer|
|
63
|
-
string.each_block 12 do |block|
|
64
|
-
chunk = @blowfish.decrypt_block Base64.decode block
|
65
|
-
buffer.concat chunk
|
66
|
-
end
|
67
|
-
end.rstrip
|
68
|
-
end
|
69
|
-
|
70
|
-
private
|
71
|
-
# Fill up the last block with null-bytes until it's a multiple of 8.
|
72
|
-
#
|
73
|
-
# @return [String] the nullpadded string.
|
74
|
-
def nullpad string
|
75
|
-
length = string.length + BlockSize - string.length % BlockSize
|
76
|
-
string.ljust length, ?\0
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
data/library/blur/evaluable.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Blur
|
4
|
-
module Evaluable
|
5
|
-
# Evaluate the contents of the input file in the context of +self+.
|
6
|
-
def evaluate_source_file path
|
7
|
-
instance_eval File.read(path), File.basename(path), 0
|
8
|
-
@__evaluated = true
|
9
|
-
rescue Exception => exception
|
10
|
-
puts "#{exception.message ^ :bold} on line #{exception.line.to_s ^ :bold}"
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
data/library/blur/extension.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Blur
|
4
|
-
# +Extension+ provides a sort of modules for scripts, for common functionality.
|
5
|
-
#
|
6
|
-
# Think of it as a kind of scripts for scripts.
|
7
|
-
class Extension
|
8
|
-
include Evaluable
|
9
|
-
include Script::DSL
|
10
|
-
include Logging
|
11
|
-
|
12
|
-
# @return the path in which the script remains.
|
13
|
-
attr_accessor :__path
|
14
|
-
# Can be used inside the script to act with the client itself.
|
15
|
-
# @return [Network::Client] the client delegate.
|
16
|
-
attr_accessor :__client
|
17
|
-
|
18
|
-
# Instantiates a new extension context and evaluates the +path+ extension
|
19
|
-
# file.
|
20
|
-
def initialize path
|
21
|
-
@__path = path
|
22
|
-
|
23
|
-
if evaluate_source_file path
|
24
|
-
log.info "Loaded extension #{@__path}"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
# Purely for DSL purposes.
|
29
|
-
#
|
30
|
-
# @example
|
31
|
-
# Extension :http do
|
32
|
-
# …
|
33
|
-
# end
|
34
|
-
def Extension name, &block
|
35
|
-
@__name = name
|
36
|
-
|
37
|
-
instance_eval &block
|
38
|
-
|
39
|
-
true
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,91 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Blur
|
4
|
-
class Network
|
5
|
-
# The +Channel+ class is used for encapsulating a channel and its properties.
|
6
|
-
#
|
7
|
-
# Users inside the channel is stored in the {#channels} attribute.
|
8
|
-
#
|
9
|
-
# Modes can be set for a channel, but Blur is not
|
10
|
-
# {http://www.irc.org/tech_docs/005.html ISupport}-compliant yet.
|
11
|
-
#
|
12
|
-
# @todo make so that channels *and* users belongs to the network, and not
|
13
|
-
# like now where the user belongs to the channel, resulting in multiple
|
14
|
-
# user instances.
|
15
|
-
class Channel
|
16
|
-
# @return [String] the channels name.
|
17
|
-
attr_accessor :name
|
18
|
-
# @return [Array] a list of users in the channel.
|
19
|
-
attr_accessor :users
|
20
|
-
# @return [String] the channels topic.
|
21
|
-
attr_accessor :topic
|
22
|
-
# @return [String] all the modes set on the channel.
|
23
|
-
attr_accessor :modes
|
24
|
-
# @return [Network] a reference to the network.
|
25
|
-
attr_accessor :network
|
26
|
-
# @return [Encryption::Fish] the channel encryption, if any.
|
27
|
-
attr_accessor :encryption
|
28
|
-
|
29
|
-
# Check whether or not this is an encrypted channel.
|
30
|
-
def encrypted?; not @encryption.nil? end
|
31
|
-
|
32
|
-
# Instantiate a user with a nickname, a network and a user list.
|
33
|
-
def initialize name, network = nil, users = []
|
34
|
-
@name = name
|
35
|
-
@users = users
|
36
|
-
@modes = ""
|
37
|
-
@network = network
|
38
|
-
|
39
|
-
users.each { |user| user.channel = self }
|
40
|
-
end
|
41
|
-
|
42
|
-
# Merge the channels mode corresponding to the leading character (+ or -).
|
43
|
-
#
|
44
|
-
# @param [String] modes the modes to merge with.
|
45
|
-
def merge_modes modes
|
46
|
-
addition = true
|
47
|
-
|
48
|
-
modes.each_char do |char|
|
49
|
-
case char
|
50
|
-
when ?+
|
51
|
-
addition = true
|
52
|
-
when ?-
|
53
|
-
addition = false
|
54
|
-
else
|
55
|
-
addition ? @modes.concat(char) : @modes.delete!(char)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
# Send a message to the channel.
|
61
|
-
#
|
62
|
-
# @param [String] message the message to send.
|
63
|
-
def say message
|
64
|
-
@network.say self, message
|
65
|
-
end
|
66
|
-
|
67
|
-
# Find a user with +nick+ as its nickname.
|
68
|
-
#
|
69
|
-
# @param [String] nick the nickname to find the user of.
|
70
|
-
def user_by_nick nick
|
71
|
-
@users.find { |user| user.nick == nick }
|
72
|
-
end
|
73
|
-
|
74
|
-
# Convert it to a debug-friendly format.
|
75
|
-
def inspect
|
76
|
-
%{#<#{self.class.name} @name=#{@name.inspect} @users=#{@users.inspect}}
|
77
|
-
end
|
78
|
-
|
79
|
-
# Called when YAML attempts to save the object, which happens when a
|
80
|
-
# scripts cache contains this user and the script is unloaded.
|
81
|
-
def to_yaml options = {}
|
82
|
-
@name.to_yaml options
|
83
|
-
end
|
84
|
-
|
85
|
-
# Get the channels name.
|
86
|
-
def to_s
|
87
|
-
@name
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
@@ -1,83 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Blur
|
4
|
-
class Network
|
5
|
-
# The +Command+ class is used for encapsulating the command-lines.
|
6
|
-
#
|
7
|
-
# Blur is using regular-expression for parsing, this is to be replaced
|
8
|
-
# with a more native way of parsing, making it much, much easier on the
|
9
|
-
# processor.
|
10
|
-
class Command
|
11
|
-
# @return [Symbol, Fixnum] the command name.
|
12
|
-
# @example
|
13
|
-
# 332 or :quit
|
14
|
-
attr_accessor :name
|
15
|
-
# @return [Array] a list of parameters.
|
16
|
-
attr_accessor :params
|
17
|
-
# @return [String] a hostname or a hostmask.
|
18
|
-
attr_accessor :prefix
|
19
|
-
|
20
|
-
# The arbitrary regex pattern.
|
21
|
-
Pattern = /^(?:[:@]([^\s]+) )?([^\s]+)(?: ((?:[^:\s][^\s]* ?)*))?(?: ?:(.*))?$/
|
22
|
-
|
23
|
-
# Parse a line and encapsulate it as a Command.
|
24
|
-
#
|
25
|
-
# @return [Command] the parsed command.
|
26
|
-
# @example
|
27
|
-
# Command.parse "ChanServ!ChanServ@services.uplink.io MODE #uplink +v mk"
|
28
|
-
# # => #<Blur::Network::Command … >
|
29
|
-
def self.parse data
|
30
|
-
match = data.strip.match Pattern
|
31
|
-
prefix, name, args, extra = match.captures
|
32
|
-
params = extra ? args.split << extra : args.split
|
33
|
-
|
34
|
-
new(name, params).tap do |this|
|
35
|
-
this.prefix = prefix
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
# Get a parameter by its +index+.
|
40
|
-
def [] index; @params[index] end
|
41
|
-
|
42
|
-
# Instantiate a command.
|
43
|
-
#
|
44
|
-
# @see Command.parse
|
45
|
-
def initialize name, params = []
|
46
|
-
@name, @params = name, params
|
47
|
-
end
|
48
|
-
|
49
|
-
# Get the sender of the command.
|
50
|
-
#
|
51
|
-
# @note the return value is a string if it's a hostname, and an openstruct
|
52
|
-
# with the attributes #nickname, #username and #hostname if it's a
|
53
|
-
# hostmask.
|
54
|
-
#
|
55
|
-
# @return [String, OpenStruct] the sender.
|
56
|
-
def sender
|
57
|
-
return @sender if @sender
|
58
|
-
|
59
|
-
if prefix =~ /^(\S+)!(\S+)@(\S+)$/
|
60
|
-
@sender = OpenStruct.new nickname: $1, username: $2, hostname: $3
|
61
|
-
else
|
62
|
-
@sender = prefix
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
# Convert it to an IRC-compliant line.
|
67
|
-
#
|
68
|
-
# @return [String] the command line.
|
69
|
-
def to_s
|
70
|
-
String.new.tap do |line|
|
71
|
-
line << "#{prefix} " if prefix
|
72
|
-
line << name.to_s
|
73
|
-
|
74
|
-
params.each_with_index do |param, index|
|
75
|
-
line << ' '
|
76
|
-
line << ?: if index == params.length - 1 and param =~ /[ :]/
|
77
|
-
line << param.to_s
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
@@ -1,106 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Blur
|
4
|
-
class Network
|
5
|
-
# The +User+ class is used for encapsulating a user and its properties.
|
6
|
-
#
|
7
|
-
# The user owns a reference to its parent channel.
|
8
|
-
#
|
9
|
-
# Modes can be set for a user, but Blur is not
|
10
|
-
# {http://www.irc.org/tech_docs/005.html ISupport}-compliant yet.
|
11
|
-
#
|
12
|
-
# @todo make so that channels *and* users belongs to the network, and not
|
13
|
-
# like now where the user belongs to the channel, resulting in multiple
|
14
|
-
# user instances.
|
15
|
-
class User
|
16
|
-
# @return [String] the users nickname.
|
17
|
-
attr_accessor :nick
|
18
|
-
# @return [String] the users username.
|
19
|
-
attr_accessor :name
|
20
|
-
# @return [String] the users hostname.
|
21
|
-
attr_accessor :host
|
22
|
-
# @return [String] all the modes set on the user.
|
23
|
-
attr_accessor :modes
|
24
|
-
# @return [Channel] a reference to the users channel.
|
25
|
-
attr_accessor :channel
|
26
|
-
# @return [Network] a reference to the network.
|
27
|
-
attr_accessor :network
|
28
|
-
|
29
|
-
# Check to see if the user is an admin (+a)
|
30
|
-
def admin?; @modes.include? "a" end
|
31
|
-
# Check to see if the user has voice (+v)
|
32
|
-
def voice?; @modes.include? "v" end
|
33
|
-
# Check to see if the user is the owner (+q)
|
34
|
-
def owner?; @modes.include? "q" end
|
35
|
-
# Check to see if the user is an operator (+o)
|
36
|
-
def operator?; @modes.include? "o" end
|
37
|
-
# Check to see if the user is an half-operator (+h)
|
38
|
-
def half_operator?; @modes.include? "h" end
|
39
|
-
|
40
|
-
# Instantiate a user with a nickname.
|
41
|
-
def initialize nick
|
42
|
-
@nick = nick
|
43
|
-
@modes = ""
|
44
|
-
|
45
|
-
if modes = prefix_to_mode(nick[0])
|
46
|
-
@nick = nick[1..-1]
|
47
|
-
@modes = modes
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
# Merge the users mode corresponding to the leading character (+ or -).
|
52
|
-
#
|
53
|
-
# @param [String] modes the modes to merge with.
|
54
|
-
def merge_modes modes
|
55
|
-
addition = true
|
56
|
-
|
57
|
-
modes.each_char do |char|
|
58
|
-
case char
|
59
|
-
when ?+
|
60
|
-
addition = true
|
61
|
-
when ?-
|
62
|
-
addition = false
|
63
|
-
else
|
64
|
-
addition ? @modes.concat(char) : @modes.delete!(char)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# Send a private message to the user.
|
70
|
-
#
|
71
|
-
# @param [String] message the message to send.
|
72
|
-
def say message
|
73
|
-
@network.say self, message
|
74
|
-
end
|
75
|
-
|
76
|
-
# Convert it to a debug-friendly format.
|
77
|
-
def inspect
|
78
|
-
%{#<#{self.class.name} @nick=#{@nick.inspect} @channel=#{@channel.name.inspect}>}
|
79
|
-
end
|
80
|
-
|
81
|
-
# Called when YAML attempts to save the object, which happens when a
|
82
|
-
# scripts cache contains this user and the script is unloaded.
|
83
|
-
def to_yaml options = {}
|
84
|
-
@nick.to_yaml options
|
85
|
-
end
|
86
|
-
|
87
|
-
# Get the users nickname.
|
88
|
-
def to_s
|
89
|
-
@nick
|
90
|
-
end
|
91
|
-
|
92
|
-
private
|
93
|
-
|
94
|
-
# Translate a nickname-prefix to a mode character.
|
95
|
-
def prefix_to_mode prefix
|
96
|
-
case prefix
|
97
|
-
when '@' then 'o'
|
98
|
-
when '+' then 'v'
|
99
|
-
when '%' then 'h'
|
100
|
-
when '&' then 'a'
|
101
|
-
when '~' then 'q'
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|