encinch 0.0.3 → 0.1.5
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/.gitignore +2 -0
- data/LICENSE.txt +1 -1
- data/README.md +34 -18
- data/Rakefile +24 -0
- data/encinch.gemspec +6 -1
- data/lib/cinch/plugins/encinch.rb +4 -0
- data/lib/cinch/plugins/encinch/encinch.rb +84 -98
- data/lib/cinch/plugins/encinch/encryption.rb +34 -37
- data/lib/cinch/plugins/encinch/extend.rb +24 -25
- data/lib/cinch/plugins/encinch/storage.rb +66 -0
- data/lib/cinch/plugins/encinch/version.rb +5 -4
- data/test/helper.rb +83 -0
- data/test/lib/encinch/encinch_spec.rb +100 -0
- data/test/lib/encinch/extend_spec.rb +171 -0
- data/test/lib/encinch/storage_spec.rb +54 -0
- data/test/lib/encinch/version_spec.rb +11 -0
- metadata +72 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eef846946cd6db68553cec479300a1a1ccdda651
|
4
|
+
data.tar.gz: 94241b2ebd043cd8487a6830f22c2493a278c135
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7d31b2e1bbdb8bb29b73621252a4fc429029c19f053e0424398ac4de72c226d0ff371d7a623a276be7ab510fbc7c74f25fc95228d192953371a420116e7aa567
|
7
|
+
data.tar.gz: 57041d4c9528d1f4f20ebb7ebf38bcfe5560d875e8ced00d2a4a056cd6f4f9895aa55676c34696b8f7ed83a05e15cf1c5d2dc6d9814d2aac37f6c2d25f635ec0
|
data/.gitignore
CHANGED
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -11,7 +11,7 @@ https://github.com/cinchrb/cinch
|
|
11
11
|
$[sudo] gem install encinch
|
12
12
|
|
13
13
|
## Example
|
14
|
-
```
|
14
|
+
```ruby
|
15
15
|
require 'cinch'
|
16
16
|
require 'cinch/plugins/encinch'
|
17
17
|
|
@@ -22,18 +22,21 @@ https://github.com/cinchrb/cinch
|
|
22
22
|
c.server = "irc.freenode.org"
|
23
23
|
c.port = 7000
|
24
24
|
c.ssl.use = true
|
25
|
-
c.channels = ["#cryptedchan", "#plaintext"]
|
25
|
+
c.channels = ["#cryptedchan", "#plaintext", "#ignorechannel"]
|
26
26
|
|
27
27
|
c.plugins.plugins = [Cinch::Plugins::EnCinch] # optionally add more plugins
|
28
28
|
|
29
29
|
c.plugins.options[Cinch::Plugins::EnCinch] = {
|
30
|
-
:
|
30
|
+
:drop => true,
|
31
|
+
:key_file => 'keys/key.yml',
|
32
|
+
:uncrypted => ["#plaintext"],
|
33
|
+
:ignore => ["#ignorechan", "ignoreperson"],
|
31
34
|
:encrypt => {
|
32
|
-
'#cryptedchan' =>
|
33
|
-
'
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
'#cryptedchan' => 'myfishkey',
|
36
|
+
'#ignorechan' => 'ignoretargetscanhaveencryptionkeys'
|
37
|
+
'cryptednick' => 'mypersonalfishkey',
|
38
|
+
:default => 'defaultfishkey'
|
39
|
+
}
|
37
40
|
}
|
38
41
|
end
|
39
42
|
end
|
@@ -41,25 +44,38 @@ https://github.com/cinchrb/cinch
|
|
41
44
|
bot.start
|
42
45
|
```
|
43
46
|
|
47
|
+
## Features
|
48
|
+
- Simple transparent message encryption for your Cinch IRC bot.
|
49
|
+
- Nicks with personal keys are updated on nick change.
|
50
|
+
- Ignore incoming encrypted messages from specific channels or users.
|
51
|
+
- Allow unencrypted messages to specific channels or users.
|
52
|
+
- Drop messages if target key not found.
|
53
|
+
- Ability to define default encryption key.
|
54
|
+
- Keys and options stored in yaml.
|
55
|
+
|
44
56
|
## Commands
|
45
|
-
None,
|
57
|
+
None. You should write your own plugin to add or remove keys, tailored to your particular needs.
|
46
58
|
|
47
59
|
|
48
60
|
## Options
|
49
61
|
### :encrypt
|
50
62
|
A hash of encryption targets and their corresponding encryption keys. Targets should all be lowercase.
|
51
|
-
|
52
|
-
The :encrypt option must be set, :default is optional.
|
63
|
+
`:default` can provide a general purpose key, possibly good for private communications with the bot or ensuring it does not respond unencrypted.
|
53
64
|
|
54
65
|
### :uncrypted
|
55
|
-
An array of channels and individuals from which the bot will not encrypt messages. All entries must be lowercase.
|
66
|
+
An array of channels and individuals from which the bot will not encrypt messages. All entries must be lowercase.
|
67
|
+
`:uncrypted` is optional.
|
56
68
|
|
57
69
|
### :ignore
|
58
|
-
An array of channels and individuals (other bots?) to ignore encrypted messages. All entries must be lower case.
|
59
|
-
|
70
|
+
An array of channels and individuals (other bots?) to ignore encrypted messages. All entries must be lower case. Note that it will not drop messages sent from the bot.
|
71
|
+
`:ignore` is optional.
|
72
|
+
|
73
|
+
### :drop
|
74
|
+
Boolean value indicating if unencrypted messages should be dropped. Targets in the `:uncrypted` array are not affected. Unnecessary if a `:default` key is set.
|
75
|
+
|
76
|
+
### :key_file
|
77
|
+
Options are now stored in yaml. The default location is 'keys/encinch.yml'. Supply an alternate location if you so desire. Location will be created if it does not exist.
|
60
78
|
|
61
79
|
## TODO
|
62
|
-
1
|
63
|
-
2
|
64
|
-
3) add commands for updating, removing and adding keys and other settings?
|
65
|
-
4) user feedback... :-)
|
80
|
+
1. key exchange
|
81
|
+
2. user feedback... :-)
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
task default: :test
|
2
|
+
|
3
|
+
task :test do
|
4
|
+
require 'rake/testtask'
|
5
|
+
|
6
|
+
files_list = Dir[File.join "test", "**", "*.rb"]
|
7
|
+
files = ENV['file'].split(',') rescue nil
|
8
|
+
verbose = !!ENV['verbose']
|
9
|
+
|
10
|
+
Rake::TestTask.new do |t|
|
11
|
+
t.verbose = verbose
|
12
|
+
t.test_files = if files
|
13
|
+
files.unshift "helper.rb"
|
14
|
+
files.map do |file|
|
15
|
+
unless index = files_list.index { |f| f.match(/\/#{file}$/) }
|
16
|
+
raise "UnknownFileError #{ file }"
|
17
|
+
end
|
18
|
+
files_list[index]
|
19
|
+
end
|
20
|
+
else
|
21
|
+
files_list
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/encinch.gemspec
CHANGED
@@ -5,7 +5,7 @@ require 'cinch/plugins/encinch/version'
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "encinch"
|
8
|
-
spec.version = EnCinch::
|
8
|
+
spec.version = ::Cinch::Plugins::EnCinch::VERSION
|
9
9
|
spec.authors = ["jfrazx"]
|
10
10
|
spec.email = ["staringblind@gmail.com"]
|
11
11
|
spec.summary = %q{Transparent blowfish encryption plugin for Cinch: An IRC Bot Building Framework}
|
@@ -20,5 +20,10 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
22
|
spec.add_runtime_dependency "cinch", "~> 2.0"
|
23
|
+
spec.add_runtime_dependency "cinch-storage", "~> 1.2"
|
23
24
|
spec.add_runtime_dependency "crypt", "~> 2.0"
|
25
|
+
|
26
|
+
spec.add_development_dependency "rake", "~> 11.0"
|
27
|
+
spec.add_development_dependency "minitest", "~> 5.8"
|
28
|
+
spec.add_development_dependency "minitest-reporters", "~> 1.1"
|
24
29
|
end
|
@@ -1,5 +1,9 @@
|
|
1
1
|
require 'cinch'
|
2
|
+
require 'cinch/storage'
|
2
3
|
require 'crypt/blowfish'
|
4
|
+
|
3
5
|
require "cinch/plugins/encinch/encryption"
|
6
|
+
require "cinch/plugins/encinch/storage"
|
4
7
|
require "cinch/plugins/encinch/encinch"
|
5
8
|
require "cinch/plugins/encinch/extend"
|
9
|
+
require "cinch/plugins/encinch/version"
|
@@ -1,137 +1,123 @@
|
|
1
1
|
|
2
2
|
module Cinch
|
3
3
|
module Plugins
|
4
|
-
|
5
|
-
|
4
|
+
class EnCinch
|
5
|
+
include Cinch::Plugin
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
def initialize(*)
|
8
|
+
super
|
9
|
+
config[:uncrypted] ||= Array.new
|
10
|
+
config[:ignore] ||= Array.new
|
11
|
+
config[:encrypt] ||= Hash.new
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
raise MissingRequiredPluginOptions unless config[:uncrypted]
|
13
|
-
|
14
|
-
end
|
15
|
-
|
16
|
-
#
|
17
|
-
# All blowfish communication should be prefixed with +OK
|
18
|
-
# capture this to start the process
|
19
|
-
#
|
20
|
-
|
21
|
-
match(/\+OK (\S+)/, use_prefix: false, strip_colors: true, method: :capture)
|
22
|
-
|
23
|
-
def capture(m, message)
|
24
|
-
target = (m.channel ? m.channel.name : m.user.nick).downcase
|
25
|
-
message = strip(m, message)
|
26
|
-
|
27
|
-
return if config[:ignore].include?(target) rescue nil
|
28
|
-
@key = config[:encrypt][target] || config[:encrypt][:default] rescue nil
|
13
|
+
shared[:encinch] = EnCinch::Storage.new(bot, config.dup)
|
14
|
+
end
|
29
15
|
|
30
|
-
|
16
|
+
#
|
17
|
+
# All blowfish communication should be prefixed with +OK
|
18
|
+
# capture this to start the process
|
19
|
+
#
|
31
20
|
|
32
|
-
|
21
|
+
match(/\+OK (\S+)/, use_prefix: false, strip_colors: true, method: :capture)
|
22
|
+
def capture(m, message)
|
23
|
+
target = (m.channel? ? m.channel.name : m.user.nick).downcase
|
33
24
|
|
34
|
-
|
35
|
-
decrypted << '\u0001' if m.action?
|
25
|
+
options = shared[:encinch].storage.data
|
36
26
|
|
37
|
-
|
27
|
+
return if options[:ignore].include?(target)
|
28
|
+
return unless key = options[:encrypt][target] || options[:encrypt][:default]
|
38
29
|
|
39
|
-
|
40
|
-
end
|
30
|
+
blowfish(key)
|
41
31
|
|
42
|
-
|
43
|
-
|
44
|
-
# NOT WORKING YET
|
45
|
-
# It appears Cinch does not emit a :notice event, unfortunate
|
46
|
-
#
|
32
|
+
message = strip(message)
|
33
|
+
decrypted = decrypt(message)
|
47
34
|
|
48
|
-
|
35
|
+
@fish = nil
|
49
36
|
|
50
|
-
|
51
|
-
|
37
|
+
decrypted << '\u0001' if m.action?
|
38
|
+
raw = modify_raw(m.raw, decrypted)
|
52
39
|
|
53
|
-
|
40
|
+
dispatch(Message.new(raw, m.bot))
|
41
|
+
end
|
54
42
|
|
55
|
-
|
56
|
-
|
43
|
+
#
|
44
|
+
# matching for key exchange
|
45
|
+
# NOT WORKING YET
|
46
|
+
#
|
47
|
+
# DH1080_INIT U5bsJHJUvzIeflIxOvz+wht3LojOx8JEz83wa5ByfN9yQlT2AlW6fjp277w4TmElwwLzOxhBA/W/7kwW5FJ4MxmZuxT9q2caMS2jbGXKpW5P6UcIQ7fg2yLqyl8KgU4X5JnC61zeoF5QwyemXdegstq90V6Cn3MqRPeeN2A7HCOeU0O52YD4A
|
48
|
+
match(/DH1080_INIT (\S+)\s*(cbc|CBC)?/, use_prefix: false, react_on: :notice, method: :key_exchange)
|
49
|
+
def key_exchange(m, key, cbc = false)
|
50
|
+
return if m.channel?
|
57
51
|
|
58
|
-
|
59
|
-
def encrypt(message)
|
60
|
-
@fish.encrypt(message)
|
61
|
-
end
|
52
|
+
debug "captured key exchange event with key: #{m.message}"
|
62
53
|
|
63
|
-
|
64
|
-
|
65
|
-
end
|
54
|
+
#TODO -- everything
|
55
|
+
end
|
66
56
|
|
67
|
-
|
68
|
-
|
69
|
-
|
57
|
+
def encrypt(message)
|
58
|
+
@fish.encrypt(message)
|
59
|
+
end
|
70
60
|
|
71
|
-
|
61
|
+
def decrypt(message)
|
62
|
+
@fish.decrypt(message)
|
63
|
+
end
|
72
64
|
|
73
|
-
|
74
|
-
|
65
|
+
def blowfish(key)
|
66
|
+
@fish = Encryption.new(key)
|
67
|
+
end
|
75
68
|
|
76
|
-
|
77
|
-
|
69
|
+
def encrypted?(data)
|
70
|
+
!!data.match(/\+OK \S+/)
|
71
|
+
end
|
78
72
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
events << [:private]
|
83
|
-
end
|
73
|
+
private
|
74
|
+
def dispatch(msg)
|
75
|
+
events = [[:catchall]]
|
84
76
|
|
85
|
-
|
86
|
-
|
87
|
-
else
|
88
|
-
events << [:notice]
|
89
|
-
end
|
77
|
+
if ["PRIVMSG", "NOTICE"].include?(msg.command)
|
78
|
+
events << [:ctcp] if msg.ctcp?
|
90
79
|
|
91
|
-
|
92
|
-
|
93
|
-
|
80
|
+
if msg.channel?
|
81
|
+
events << [:channel]
|
82
|
+
else
|
83
|
+
events << [:private]
|
94
84
|
end
|
95
85
|
|
96
|
-
|
97
|
-
|
86
|
+
if msg.command == "PRIVMSG"
|
87
|
+
events << [:message]
|
88
|
+
end
|
98
89
|
|
99
|
-
if msg.
|
100
|
-
events << [:
|
90
|
+
if msg.action?
|
91
|
+
events << [:action]
|
101
92
|
end
|
93
|
+
end
|
102
94
|
|
103
|
-
|
95
|
+
meth = "on_#{msg.command.downcase}"
|
96
|
+
__send__(meth, msg, events) if respond_to?(meth, true)
|
104
97
|
|
105
|
-
|
98
|
+
events << [:error] if msg.error?
|
106
99
|
|
107
|
-
|
108
|
-
msg.events.each do |event, *args|
|
109
|
-
msg.bot.handlers.dispatch(event, msg, *args)
|
110
|
-
end unless encrypted?(msg.raw)
|
111
|
-
end
|
100
|
+
events << [msg.command.downcase.intern]
|
112
101
|
|
113
|
-
|
114
|
-
# TODO: strip ctcp? others?
|
115
|
-
#
|
102
|
+
msg.events = events
|
116
103
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
104
|
+
#if its still encrypted for whatever reason we will not be processing it again
|
105
|
+
msg.events.each do |event, *args|
|
106
|
+
msg.bot.handlers.dispatch(event, msg, *args)
|
107
|
+
end unless encrypted?(msg.raw)
|
108
|
+
end
|
122
109
|
|
123
|
-
|
124
|
-
|
125
|
-
|
110
|
+
def strip(data)
|
111
|
+
data.sub(/\u0001$/, '')
|
112
|
+
end
|
126
113
|
|
127
|
-
|
128
|
-
|
129
|
-
|
114
|
+
#
|
115
|
+
# replace the encrypted message with the decrypted
|
116
|
+
#
|
130
117
|
|
131
|
-
|
132
|
-
|
133
|
-
data
|
134
|
-
end
|
118
|
+
def modify_raw(data, decrypted)
|
119
|
+
data.sub(/\+OK \S+(\s+\S+)?/, decrypted)
|
135
120
|
end
|
121
|
+
end
|
136
122
|
end
|
137
123
|
end
|
@@ -3,14 +3,14 @@
|
|
3
3
|
# https://github.com/cinchrb/cinch/tree/feature/fish
|
4
4
|
# or from weechat's fish plugin
|
5
5
|
# https://github.com/weechat/scripts/blob/master/ruby/weefish.rb
|
6
|
-
#
|
6
|
+
#
|
7
7
|
|
8
8
|
module Cinch
|
9
9
|
module Plugins
|
10
10
|
class EnCinch
|
11
11
|
class Encryption
|
12
12
|
module Base64
|
13
|
-
|
13
|
+
|
14
14
|
Alphabet = "./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".freeze
|
15
15
|
|
16
16
|
def self.encode(data)
|
@@ -31,28 +31,28 @@ module Cinch
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
|
34
|
+
res
|
35
35
|
end
|
36
36
|
|
37
37
|
def self.decode(data)
|
38
38
|
res = String.new
|
39
39
|
data = data.dup.force_encoding("BINARY")
|
40
|
+
|
40
41
|
data.chars.each_slice(12) do |slice|
|
41
42
|
slice = slice.join
|
42
43
|
left = right = 0
|
43
|
-
|
44
|
-
|
45
|
-
right |= Alphabet.index(p) << (i * 6)
|
44
|
+
slice[0..5].each_char.with_index do |pi, i|
|
45
|
+
right |= Alphabet.index(pi) << (i * 6)
|
46
46
|
end
|
47
47
|
|
48
|
-
slice[6..11].each_char.with_index do |
|
49
|
-
left |= Alphabet.index(
|
48
|
+
slice[6..11].each_char.with_index do |pi, i|
|
49
|
+
left |= Alphabet.index(pi) << (i * 6)
|
50
50
|
end
|
51
51
|
|
52
52
|
res << [left, right].pack('L>L>')
|
53
53
|
end
|
54
54
|
|
55
|
-
|
55
|
+
res
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
@@ -60,48 +60,45 @@ module Cinch
|
|
60
60
|
def initialize(key)
|
61
61
|
@blowfish = Crypt::Blowfish.new(key)
|
62
62
|
end
|
63
|
-
|
64
|
-
def encrypt(
|
65
|
-
|
63
|
+
|
64
|
+
def encrypt(data)
|
65
|
+
data = pad(data, 8)
|
66
66
|
result = String.new
|
67
|
-
|
68
|
-
num_block =
|
67
|
+
|
68
|
+
num_block = data.length / 8
|
69
69
|
num_block.times do |n|
|
70
|
-
block =
|
70
|
+
block = data[n * 8..(n + 1) * 8 - 1]
|
71
71
|
enc = @blowfish.encrypt_block(block)
|
72
72
|
result += Base64.encode(enc)
|
73
73
|
end
|
74
|
-
|
75
|
-
|
74
|
+
|
75
|
+
"+OK " << result
|
76
76
|
end
|
77
|
-
|
78
|
-
def decrypt(
|
79
|
-
|
80
|
-
|
77
|
+
|
78
|
+
def decrypt(data)
|
79
|
+
data.sub!(/^\+OK\s+/, '')
|
80
|
+
|
81
|
+
return nil if not data.length % 12 == 0
|
82
|
+
|
81
83
|
result = String.new
|
82
|
-
|
83
|
-
num_block = (
|
84
|
+
|
85
|
+
num_block = (data.length / 12).to_i
|
84
86
|
num_block.times do |n|
|
85
|
-
block = Base64.decode(
|
87
|
+
block = Base64.decode( data[n*12..(n + 1)*12-1] )
|
86
88
|
result += @blowfish.decrypt_block(block)
|
87
89
|
end
|
88
|
-
|
89
|
-
return result.gsub(/\0*$/, "")
|
90
|
-
end
|
91
90
|
|
92
|
-
|
93
|
-
# generate a key for key exchange
|
91
|
+
result.gsub(/\0*$/, '')
|
94
92
|
end
|
95
|
-
|
93
|
+
|
96
94
|
private
|
97
|
-
|
98
|
-
def pad(text, n=8)
|
99
|
-
pad_num = n - (text.length % n)
|
100
|
-
if pad_num > 0 and pad_num != n
|
101
|
-
pad_num.times { text += 0.chr }
|
102
|
-
end
|
103
95
|
|
104
|
-
|
96
|
+
def pad(data, n=8)
|
97
|
+
pad_num = n - (data.length % n)
|
98
|
+
|
99
|
+
pad_num.times { data += 0.chr } if pad_num > 0 and pad_num != n
|
100
|
+
|
101
|
+
data
|
105
102
|
end
|
106
103
|
end
|
107
104
|
end
|
@@ -1,47 +1,46 @@
|
|
1
1
|
|
2
2
|
module Cinch
|
3
|
-
module Exceptions
|
4
|
-
|
5
|
-
# error to raise for missing required plugin options
|
6
|
-
class MissingRequiredPluginOptions < Generic
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
|
11
3
|
class IRC
|
12
4
|
|
5
|
+
# alias instead of modify directly
|
6
|
+
alias :encinch_send :send
|
7
|
+
|
13
8
|
# Send a message to the server.
|
14
9
|
# @param [String] msg
|
15
10
|
# @return [void]
|
16
11
|
def send(msg)
|
17
|
-
|
18
|
-
# TODO match and modify ACTION
|
19
12
|
if msg.match(/(PRIVMSG|NOTICE)/) && !msg.match(/\+OK (\S+)/)
|
13
|
+
_, _, target, message = *msg.match(/(\S+) (\S+) :(.*)/m)
|
14
|
+
target.downcase!
|
20
15
|
|
21
|
-
|
22
|
-
|
16
|
+
unless message.empty?
|
17
|
+
# retrieve bot options
|
18
|
+
options = @bot.config.shared[:encinch].storage.data
|
23
19
|
|
24
|
-
|
25
|
-
|
20
|
+
# ignore if target is in the 'uncrypted' array
|
21
|
+
unless options[:uncrypted].include?(target)
|
26
22
|
|
27
|
-
|
28
|
-
|
23
|
+
# match ctcp? and action messages
|
24
|
+
if matched = message.match(/\001ACTION\s(.+)\001/)
|
25
|
+
message = matched[-1]
|
26
|
+
elsif message =~ /\001.+\001/
|
27
|
+
return encinch_send(msg)
|
28
|
+
end
|
29
29
|
|
30
|
-
#
|
31
|
-
|
30
|
+
# key exists
|
31
|
+
if key = (options[:encrypt][target] || options[:encrypt][:default])
|
32
32
|
|
33
|
-
|
34
|
-
encrypted = fish.encrypt(message)
|
33
|
+
encrypted = Cinch::Plugins::EnCinch::Encryption.new(key).encrypt(message)
|
35
34
|
msg.sub!(message, encrypted)
|
35
|
+
|
36
|
+
else
|
37
|
+
return if options[:drop]
|
36
38
|
end
|
37
39
|
end
|
38
40
|
end
|
39
|
-
end
|
41
|
+
end
|
40
42
|
|
41
|
-
|
43
|
+
encinch_send(msg)
|
42
44
|
end
|
43
|
-
|
44
|
-
private
|
45
|
-
|
46
45
|
end
|
47
46
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Cinch
|
2
|
+
module Plugins
|
3
|
+
class EnCinch
|
4
|
+
class Storage
|
5
|
+
include Cinch::Plugin
|
6
|
+
|
7
|
+
attr_reader :storage
|
8
|
+
|
9
|
+
def initialize(bot, data)
|
10
|
+
super(bot)
|
11
|
+
|
12
|
+
file = data.delete(:key_file) || 'keys/encinch.yml'
|
13
|
+
make_dirp(file)
|
14
|
+
|
15
|
+
@storage = ::Cinch::Storage.new(file, data)
|
16
|
+
|
17
|
+
@storage.data.merge!(data) do |key, x, y|
|
18
|
+
case x
|
19
|
+
when Hash
|
20
|
+
x.merge!(y || {})
|
21
|
+
when Array
|
22
|
+
x.concat(y || []).uniq
|
23
|
+
when NilClass
|
24
|
+
y
|
25
|
+
else
|
26
|
+
if y.nil? || y.empty?
|
27
|
+
x
|
28
|
+
else
|
29
|
+
y
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
@storage.data[:drop] ||= false
|
35
|
+
|
36
|
+
save
|
37
|
+
end
|
38
|
+
|
39
|
+
# listen to nick change and update
|
40
|
+
|
41
|
+
listen_to :nick
|
42
|
+
def listen(m)
|
43
|
+
if @storage.data[:encrypt][m.user.last_nick.downcase]
|
44
|
+
@storage.data[:encrypt][m.user.nick.downcase] = @storage.data[:encrypt].delete(m.user.last_nick.downcase)
|
45
|
+
save
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# save keys in yaml
|
51
|
+
#
|
52
|
+
def save
|
53
|
+
synchronize(:encinch_storage_save) do
|
54
|
+
@storage.save
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def make_dirp(file)
|
59
|
+
path = File.expand_path(File.dirname(file))
|
60
|
+
FileUtils.mkdir_p(path) unless Dir.exist?(path)
|
61
|
+
end
|
62
|
+
private :make_dirp
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'minitest/reporters'
|
3
|
+
require_relative '../lib/cinch/plugins/encinch'
|
4
|
+
|
5
|
+
reporter_options = { color: true, slow_count: 5 }
|
6
|
+
Minitest::Reporters.use! [Minitest::Reporters::DefaultReporter.new(reporter_options)]
|
7
|
+
|
8
|
+
if ENV["SIMPLECOV"]
|
9
|
+
begin
|
10
|
+
require 'simplecov'
|
11
|
+
SimpleCov.start
|
12
|
+
rescue LoadError
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
unless Object.const_defined? 'Cinch'
|
17
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
18
|
+
require 'cinch'
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
class TestCase < MiniTest::Test
|
23
|
+
def self.test(name, &block)
|
24
|
+
define_method("test_" + name, &block) if block
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Bot
|
29
|
+
attr_accessor :ulist
|
30
|
+
attr_reader :message, :event
|
31
|
+
|
32
|
+
@@defined = false
|
33
|
+
|
34
|
+
def initialize(*)
|
35
|
+
@opts = Hash.new
|
36
|
+
@ulist = Array.new
|
37
|
+
@share = Hash.new
|
38
|
+
method_maker unless @@defined
|
39
|
+
end
|
40
|
+
|
41
|
+
def method_maker
|
42
|
+
[
|
43
|
+
:config, :plugins, :loggers, :handlers, :debug, :register,
|
44
|
+
:warn, :prefix, :suffix,:irc, :network, :user_list
|
45
|
+
].each do |method|
|
46
|
+
self.class.send :define_method, method do |*|
|
47
|
+
self
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
@@defined = true
|
52
|
+
end
|
53
|
+
|
54
|
+
def isupport(*)
|
55
|
+
[]
|
56
|
+
end
|
57
|
+
|
58
|
+
def find_ensured(*)
|
59
|
+
@ulist.first
|
60
|
+
end
|
61
|
+
private :method_maker
|
62
|
+
|
63
|
+
def options
|
64
|
+
@opts
|
65
|
+
end
|
66
|
+
|
67
|
+
def synchronize(name, &block)
|
68
|
+
yield block if block_given?
|
69
|
+
end
|
70
|
+
|
71
|
+
def shared
|
72
|
+
@share
|
73
|
+
end
|
74
|
+
|
75
|
+
def ngametv?
|
76
|
+
false
|
77
|
+
end
|
78
|
+
|
79
|
+
def dispatch(event, message, *args)
|
80
|
+
@event = event
|
81
|
+
@message = message
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Cinch
|
2
|
+
module Plugins
|
3
|
+
class EnCinch
|
4
|
+
|
5
|
+
def config
|
6
|
+
@bot.options[self.class]
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Message
|
12
|
+
def privmsg_channel_name(s)
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class EnCinchTest < TestCase
|
19
|
+
parallelize_me!
|
20
|
+
|
21
|
+
def setup
|
22
|
+
bot = Bot.new
|
23
|
+
bot.options[Cinch::Plugins::EnCinch] = { encrypt: Hash.new }
|
24
|
+
@encinch = Cinch::Plugins::EnCinch.new(bot)
|
25
|
+
@message = ":encrypt_me!~encrypt_me@192.168.1.1 PRIVMSG #encinch :hello"
|
26
|
+
@encrypted_message = ":encrypt_me!~encrypt_me@192.168.1.1 PRIVMSG #encinch :+OK 3hcMC.j7WrK."
|
27
|
+
@key = "thisisafishkey"
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_plugin_options_retrieval
|
31
|
+
assert_equal @encinch.shared[:encinch].storage.data, { ignore: [], uncrypted:[], encrypt: {}, drop: false }
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_encrypt_message
|
35
|
+
encrypted = @encinch.blowfish(@key).encrypt(@message)
|
36
|
+
assert_equal false, @encinch.encrypted?(@message)
|
37
|
+
assert_equal true, @encinch.encrypted?(encrypted)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_decrypt_message
|
41
|
+
encrypted = @encinch.blowfish(@key).encrypt(@message)
|
42
|
+
assert_equal false, @encinch.encrypted?(@message)
|
43
|
+
assert_equal true, @encinch.encrypted?(encrypted)
|
44
|
+
|
45
|
+
decrypted = @encinch.decrypt(encrypted)
|
46
|
+
|
47
|
+
assert_equal @message, decrypted
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_add_user_to_ignore
|
51
|
+
@encinch.shared[:encinch].storage.data[:ignore] << "ignore_me"
|
52
|
+
assert_equal ["ignore_me"], @encinch.shared[:encinch].storage.data[:ignore]
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_add_user_to_uncrypted
|
56
|
+
@encinch.shared[:encinch].storage.data[:uncrypted] << "plain_text"
|
57
|
+
assert_equal ["plain_text"], @encinch.shared[:encinch].storage.data[:uncrypted]
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_add_user_to_encrypted
|
61
|
+
@encinch.shared[:encinch].storage.data[:encrypt]["encrypt_me"] = "myencryptionkey"
|
62
|
+
expected = { "encrypt_me" => "myencryptionkey" }
|
63
|
+
assert_equal expected, @encinch.shared[:encinch].storage.data[:encrypt]
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_capture_ignore_user
|
67
|
+
@encinch.shared[:encinch].storage.data[:ignore] << ignore = "ignore_me"
|
68
|
+
encrypted_message = ":encrypt_me!~encrypt_me@192.168.1.1 PRIVMSG ignore_me :+OK 3hcMC.j7WrK."
|
69
|
+
|
70
|
+
user = Cinch::User.new(ignore, @encinch.bot)
|
71
|
+
@encinch.bot.ulist << user
|
72
|
+
|
73
|
+
message = Cinch::Message.new(encrypted_message, @encinch.bot)
|
74
|
+
|
75
|
+
result = @encinch.capture(message, message.message)
|
76
|
+
|
77
|
+
assert_nil result
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_capture_no_key
|
81
|
+
encrypted_message = ":encrypt_me!~encrypt_me@192.168.1.1 PRIVMSG no_key :+OK 3hcMC.j7WrK."
|
82
|
+
user = Cinch::User.new("no_key", @encinch.bot)
|
83
|
+
@encinch.bot.ulist << user
|
84
|
+
message = Cinch::Message.new(encrypted_message, @encinch.bot)
|
85
|
+
result = @encinch.capture(message, message.message)
|
86
|
+
|
87
|
+
assert_nil result
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_capture_user_encrypted_message
|
91
|
+
@encinch.shared[:encinch].storage.data[:encrypt]["encrypt_me"] = @key
|
92
|
+
user = Cinch::User.new("encrypt_me", @encinch.bot)
|
93
|
+
@encinch.bot.ulist << user
|
94
|
+
|
95
|
+
message = Cinch::Message.new(@encrypted_message, @encinch.bot)
|
96
|
+
|
97
|
+
@encinch.capture(message, message.message)
|
98
|
+
assert_equal "hello", @encinch.bot.message.message
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
module Cinch
|
2
|
+
class IRC
|
3
|
+
attr_reader :message
|
4
|
+
def encinch_send(msg)
|
5
|
+
@message = msg
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class ExtendTest < TestCase
|
11
|
+
parallelize_me!
|
12
|
+
|
13
|
+
def setup
|
14
|
+
bot = Bot.new
|
15
|
+
bot.options[Cinch::Plugins::EnCinch] = { encrypt: Hash.new }
|
16
|
+
@irc = Cinch::IRC.new(bot)
|
17
|
+
@encinch = Cinch::Plugins::EnCinch.new(bot)
|
18
|
+
@message = "hello"
|
19
|
+
@channel = "PRIVMSG #encinch :"
|
20
|
+
@user = "PRIVMSG encinch :"
|
21
|
+
@key = "thisisafishkey"
|
22
|
+
@encrypted = @encinch.blowfish(@key).encrypt(@message)
|
23
|
+
@lines = ["Lorem ipsum dolor sit amet", "dicat admodum est cu", "ne ferri soleat dolorum usu.", "Mel cu aliquid docendi temporibus", "at pri odio congue interesset. Quot assentior vis te", "ius ad wisi placerat deserunt", "facete insolens pri ex. An duo tantas veritus. Augue commodo sed ei", "ius quod eruditi lobortis id", "ne epicurei consetetur vim. Quo no debitis electram deseruisse", "quis senserit ei vis."]
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_send_encrypted_message_pass_through
|
27
|
+
@irc.send(@channel + @encrypted)
|
28
|
+
assert_equal @channel + @encrypted, @irc.message
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_send_uncrypted_message_encrypt
|
32
|
+
@encinch.shared[:encinch].storage.data[:encrypt]["#encinch"] = @key
|
33
|
+
@irc.send(@channel + @message)
|
34
|
+
assert_equal @channel + @encrypted, @irc.message
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_send_larger_chunks
|
38
|
+
@encinch.shared[:encinch].storage.data[:encrypt]["#encinch"] = @key
|
39
|
+
@lines.each do |line|
|
40
|
+
@irc.send(@channel + line)
|
41
|
+
crypted = @encinch.blowfish(@key).encrypt(line)
|
42
|
+
assert_equal @channel + crypted, @irc.message
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_send_default_key
|
47
|
+
default = "thisisdefaultkey"
|
48
|
+
@encinch.shared[:encinch].storage.data[:encrypt][:default] = default
|
49
|
+
|
50
|
+
@lines.each do |line|
|
51
|
+
@irc.send(@channel + line)
|
52
|
+
crypted = @encinch.blowfish(default).encrypt(line)
|
53
|
+
assert_equal @channel + crypted, @irc.message
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_send_uncrypted_message_bypass
|
58
|
+
@encinch.shared[:encinch].storage.data[:uncrypted] << '#encinch'
|
59
|
+
@irc.send(@channel + @message)
|
60
|
+
assert_equal @channel + @message, @irc.message
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_send_user_default_key
|
64
|
+
default = "thisisdefaultkey"
|
65
|
+
@encinch.shared[:encinch].storage.data[:encrypt][:default] = default
|
66
|
+
|
67
|
+
@lines.each do |line|
|
68
|
+
@irc.send(@user + line)
|
69
|
+
crypted = @encinch.blowfish(default).encrypt(line)
|
70
|
+
assert_equal @user + crypted, @irc.message
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_send_text_with_newline_character
|
75
|
+
string = "this is some text with \n a new line character"
|
76
|
+
@encinch.shared[:encinch].storage.data[:encrypt]["encinch"] = @key
|
77
|
+
@irc.send(@user + string)
|
78
|
+
|
79
|
+
crypted = @encinch.blowfish(@key).encrypt(string)
|
80
|
+
|
81
|
+
assert_equal @user + crypted, @irc.message
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_send_text_with_return_character
|
85
|
+
string = "this is some text with \r a return character"
|
86
|
+
@encinch.shared[:encinch].storage.data[:encrypt]["encinch"] = @key
|
87
|
+
@irc.send(@user + string)
|
88
|
+
|
89
|
+
crypted = @encinch.blowfish(@key).encrypt(string)
|
90
|
+
|
91
|
+
assert_equal @user + crypted, @irc.message
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_send_text_with_tab_character
|
95
|
+
string = "this is some text with \t a tab character"
|
96
|
+
@encinch.shared[:encinch].storage.data[:encrypt]["encinch"] = @key
|
97
|
+
@irc.send(@user + string)
|
98
|
+
|
99
|
+
crypted = @encinch.blowfish(@key).encrypt(string)
|
100
|
+
|
101
|
+
assert_equal @user + crypted, @irc.message
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_send_text_with_newline_return_tab_characters
|
105
|
+
string = "this is some text with \t a tab character and a \r return character, and a \n newline character"
|
106
|
+
@encinch.shared[:encinch].storage.data[:encrypt]["encinch"] = @key
|
107
|
+
@irc.send(@user + string)
|
108
|
+
|
109
|
+
crypted = @encinch.blowfish(@key).encrypt(string)
|
110
|
+
|
111
|
+
assert_equal @user + crypted, @irc.message
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_send_action_message
|
115
|
+
string = "this is some action text"
|
116
|
+
@encinch.shared[:encinch].storage.data[:encrypt]["encinch"] = @key
|
117
|
+
@irc.send("#{ @user }\u0001ACTION #{ string }\u0001")
|
118
|
+
crypted = @encinch.blowfish(@key).encrypt(string)
|
119
|
+
|
120
|
+
assert_equal "#{ @user }\u0001ACTION #{ crypted }\u0001", @irc.message
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_send_finger_pass_through
|
124
|
+
@encinch.shared[:encinch].storage.data[:encrypt]["encinch"] = @key
|
125
|
+
@irc.send("#{ @user }\u0001FINGER\u0001")
|
126
|
+
|
127
|
+
assert_equal "#{ @user }\u0001FINGER\u0001", @irc.message
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_send_empty_message
|
131
|
+
@encinch.shared[:encinch].storage.data[:encrypt]["encinch"] = @key
|
132
|
+
@irc.send(@user + String.new)
|
133
|
+
|
134
|
+
assert_equal @user + String.new, @irc.message
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_send_long_empty_message
|
138
|
+
string = " "
|
139
|
+
@encinch.shared[:encinch].storage.data[:encrypt]["encinch"] = @key
|
140
|
+
@irc.send(@user + string)
|
141
|
+
crypted = @encinch.blowfish(@key).encrypt(string)
|
142
|
+
|
143
|
+
assert_equal @user + crypted, @irc.message
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_send_drop_channel_message
|
147
|
+
@encinch.shared[:encinch].storage.data[:drop] = true
|
148
|
+
@irc.send(@channel + @message)
|
149
|
+
assert_nil @irc.message
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_send_drop_user_message
|
153
|
+
@encinch.shared[:encinch].storage.data[:drop] = true
|
154
|
+
@irc.send(@user + @message)
|
155
|
+
assert_nil @irc.message
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_send_allow_uncrypted_channel_no_drop
|
159
|
+
@encinch.shared[:encinch].storage.data[:drop] = true
|
160
|
+
@encinch.shared[:encinch].storage.data[:uncrypted] << '#encinch'
|
161
|
+
@irc.send(@channel + @message)
|
162
|
+
assert_equal @channel + @message, @irc.message
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_send_allow_uncrypted_user_no_drop
|
166
|
+
@encinch.shared[:encinch].storage.data[:drop] = true
|
167
|
+
@encinch.shared[:encinch].storage.data[:uncrypted] << 'encinch'
|
168
|
+
@irc.send(@user + @message)
|
169
|
+
assert_equal @user + @message, @irc.message
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class StorageTest < TestCase
|
2
|
+
def setup
|
3
|
+
bot = Bot.new
|
4
|
+
@options = {
|
5
|
+
ignore: Array.new,
|
6
|
+
uncrypted: Array.new,
|
7
|
+
encrypt: Hash.new
|
8
|
+
}
|
9
|
+
|
10
|
+
@storage = Cinch::Plugins::EnCinch::Storage.new(bot, @options)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_retrieve_options
|
14
|
+
@options[:drop] = false
|
15
|
+
assert_equal @options, options
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_add_ignore_options
|
19
|
+
opts = options[:ignore]
|
20
|
+
assert_equal @options[:ignore], opts
|
21
|
+
|
22
|
+
opts << 'ignore_me'
|
23
|
+
|
24
|
+
assert_equal opts, options[:ignore]
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_add_uncrypted_options
|
28
|
+
opts = options[:uncrypted]
|
29
|
+
assert_equal @options[:uncrypted], opts
|
30
|
+
|
31
|
+
opts << 'uncrypt_me'
|
32
|
+
|
33
|
+
assert_equal opts, options[:uncrypted]
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_add_encryption_target
|
37
|
+
opts = options[:encrypt]
|
38
|
+
|
39
|
+
assert_equal @options[:encrypt], opts
|
40
|
+
|
41
|
+
opts[:default] = 'thisisafishkey'
|
42
|
+
|
43
|
+
assert_equal options[:encrypt], opts
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_save_storage
|
47
|
+
assert_instance_of File, @storage.save
|
48
|
+
end
|
49
|
+
|
50
|
+
def options
|
51
|
+
@storage.storage.data
|
52
|
+
end
|
53
|
+
private :options
|
54
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class VersionTest < TestCase
|
2
|
+
parallelize_me!
|
3
|
+
|
4
|
+
def test_version_should_be_a_string
|
5
|
+
assert_instance_of String, ::Cinch::Plugins::EnCinch::VERSION
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_version_string_should_be_series_of_integers
|
9
|
+
refute_empty ::Cinch::Plugins::EnCinch::VERSION.scan(/\d+/).map(&:to_i)
|
10
|
+
end
|
11
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: encinch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jfrazx
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-05-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cinch
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: cinch-storage
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.2'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: crypt
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,6 +52,48 @@ dependencies:
|
|
38
52
|
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: '2.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '11.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '11.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: minitest
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '5.8'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '5.8'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: minitest-reporters
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.1'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.1'
|
41
97
|
description: ''
|
42
98
|
email:
|
43
99
|
- staringblind@gmail.com
|
@@ -48,12 +104,19 @@ files:
|
|
48
104
|
- ".gitignore"
|
49
105
|
- LICENSE.txt
|
50
106
|
- README.md
|
107
|
+
- Rakefile
|
51
108
|
- encinch.gemspec
|
52
109
|
- lib/cinch/plugins/encinch.rb
|
53
110
|
- lib/cinch/plugins/encinch/encinch.rb
|
54
111
|
- lib/cinch/plugins/encinch/encryption.rb
|
55
112
|
- lib/cinch/plugins/encinch/extend.rb
|
113
|
+
- lib/cinch/plugins/encinch/storage.rb
|
56
114
|
- lib/cinch/plugins/encinch/version.rb
|
115
|
+
- test/helper.rb
|
116
|
+
- test/lib/encinch/encinch_spec.rb
|
117
|
+
- test/lib/encinch/extend_spec.rb
|
118
|
+
- test/lib/encinch/storage_spec.rb
|
119
|
+
- test/lib/encinch/version_spec.rb
|
57
120
|
homepage: https://github.com/jfrazx/EnCinch
|
58
121
|
licenses:
|
59
122
|
- MIT
|
@@ -78,4 +141,10 @@ rubygems_version: 2.2.2
|
|
78
141
|
signing_key:
|
79
142
|
specification_version: 4
|
80
143
|
summary: 'Transparent blowfish encryption plugin for Cinch: An IRC Bot Building Framework'
|
81
|
-
test_files:
|
144
|
+
test_files:
|
145
|
+
- test/helper.rb
|
146
|
+
- test/lib/encinch/encinch_spec.rb
|
147
|
+
- test/lib/encinch/extend_spec.rb
|
148
|
+
- test/lib/encinch/storage_spec.rb
|
149
|
+
- test/lib/encinch/version_spec.rb
|
150
|
+
has_rdoc:
|