blur 1.8.6 → 2.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 +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
|