lita-discord 0.1.0
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 +7 -0
- data/.gitignore +20 -0
- data/.travis.yml +8 -0
- data/Gemfile +3 -0
- data/README.md +31 -0
- data/Rakefile +6 -0
- data/lib/lita/adapters/discord/api.rb +64 -0
- data/lib/lita/adapters/discord/client.rb +87 -0
- data/lib/lita/adapters/discord/token_cache.rb +147 -0
- data/lib/lita/adapters/discord.rb +39 -0
- data/lib/lita-discord.rb +7 -0
- data/lita-discord.gemspec +29 -0
- data/locales/en.yml +4 -0
- data/spec/lita/adapters/discord_spec.rb +4 -0
- data/spec/spec_helper.rb +6 -0
- metadata +202 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a37c01b611457e695c4a7f73d5c46b79058ee502
|
4
|
+
data.tar.gz: 75d7e3923aead4abb4ecc9010c53a906c3f1da70
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 48dcfc7e93bf466930fd4cd209cb384ce3824ad86c5986d625ef1975d994402fe8818e0b70be27582844bac60e85ec1eab9f2acada0dd2e79ac3a501da973d1d
|
7
|
+
data.tar.gz: 2dbd6a02802ef02058a49c02469743da17eee803426656e2561e57408bbb6e596e71b05f654a83a208b6f1c78dbd14f290419f7ace08504cfef770c9dbbb1b34
|
data/.gitignore
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
lita_config.rb
|
19
|
+
lib/lita/adapters/discord/template.rb
|
20
|
+
*.json
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# lita-discord
|
2
|
+
|
3
|
+
[](https://travis-ci.org/kyleboe/lita-discord)
|
4
|
+
|
5
|
+
**lita-discord** is an adapter for [Lita](https://www.lita.io/) that allows you to use the robot with [Discord](https://discordapp.com/)
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add lita-discord to your Lita instance's Gemfile:
|
10
|
+
|
11
|
+
``` ruby
|
12
|
+
gem "lita-discord"
|
13
|
+
```
|
14
|
+
|
15
|
+
## Configuration
|
16
|
+
|
17
|
+
You will need to go to the discord website and make an account that will be the account that your bot will function as. (Fix this awful wording later)
|
18
|
+
|
19
|
+
### Required attributes
|
20
|
+
|
21
|
+
* `email` (String) - The email of the account of the bot you created
|
22
|
+
* `password` (String) - The password of the account of the bot you created
|
23
|
+
|
24
|
+
|
25
|
+
### Optional attributes
|
26
|
+
|
27
|
+
TODO: Put the optional attributes here
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
TODO: Describe the plugin's features and how to use them.
|
data/Rakefile
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Lita
|
5
|
+
module Adapters
|
6
|
+
class Discord < Adapter
|
7
|
+
class API
|
8
|
+
APIBASE = 'https://discordapp.com/api'.freeze
|
9
|
+
|
10
|
+
def user_agent
|
11
|
+
# This particular string is required by the Discord devs.
|
12
|
+
required = "lita-discord (https://github.com/kyleboe/lita-discord, v0.1.0)"
|
13
|
+
@bot_name ||= ''
|
14
|
+
|
15
|
+
"rest-client/#{RestClient::VERSION} #{RUBY_ENGINE}/#{RUBY_VERSION}p#{RUBY_PATCHLEVEL} lita-discord/0.1.0 #{required} #{@bot_name}"
|
16
|
+
end
|
17
|
+
|
18
|
+
# Referenced https://github.com/meew0/discordrb/blob/9897dad08370d4de5de738c8f6c27b8c7764c429/lib/discordrb/api.rb#L35
|
19
|
+
def raw_request(type, attributes)
|
20
|
+
RestClient.send(type, *attributes)
|
21
|
+
rescue RestClient::Forbidden
|
22
|
+
raise Lita.logger.debug("The bot doesn't have the required permission to do this!")
|
23
|
+
end
|
24
|
+
|
25
|
+
def request(type, *attributes)
|
26
|
+
# Add a custom user agent
|
27
|
+
attributes.last[:user_agent] = user_agent if attributes.last.is_a? Hash
|
28
|
+
response = raw_request(type, attributes)
|
29
|
+
|
30
|
+
while response.code == 429
|
31
|
+
wait_seconds = response[:retry_after].to_i / 1000.0
|
32
|
+
Lita.logger.debug("WARNING: Discord rate limiting will cause a delay of #{wait_seconds} seconds for the request: #{type} #{attributes}")
|
33
|
+
sleep wait_seconds / 1000.0
|
34
|
+
response = raw_request(type, attributes)
|
35
|
+
end
|
36
|
+
response
|
37
|
+
end
|
38
|
+
|
39
|
+
# Make an avatar URL from the user and avatar IDs
|
40
|
+
def avatar_url(user_id, avatar_id)
|
41
|
+
"#{APIBASE}/users/#{user_id}/avatars/#{avatar_id}.jpg"
|
42
|
+
end
|
43
|
+
|
44
|
+
# Login to the server
|
45
|
+
def login(email, password)
|
46
|
+
request( :post, "#{APIBASE}/auth/login", email: email, password: password )
|
47
|
+
end
|
48
|
+
|
49
|
+
# Logout from the server
|
50
|
+
def logout(token)
|
51
|
+
request( :post, "#{APIBASE}/auth/logout", nil, Authorization: token )
|
52
|
+
end
|
53
|
+
|
54
|
+
def validate_token(token)
|
55
|
+
request( :post, "#{APIBASE}/auth/login",{}.to_json, Authorization: token, content_type: :json )
|
56
|
+
end
|
57
|
+
|
58
|
+
def user(token, user_id)
|
59
|
+
request( :get, "#{APIBASE}/users/#{user_id}", Authorization: token )
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require 'faye/websocket'
|
3
|
+
require 'eventmachine'
|
4
|
+
require 'lita/adapters/discord/api'
|
5
|
+
require 'lita/adapters/discord/token_cache'
|
6
|
+
|
7
|
+
module Lita
|
8
|
+
module Adapters
|
9
|
+
class Discord < Adapter
|
10
|
+
class Client
|
11
|
+
def initialize(email, password)
|
12
|
+
@email = email
|
13
|
+
@password = password
|
14
|
+
@token_cache = TokenCache.new
|
15
|
+
@channels = {}
|
16
|
+
@users = {}
|
17
|
+
@restricted_channels = []
|
18
|
+
@event_threads = []
|
19
|
+
@current_thread = 0
|
20
|
+
end
|
21
|
+
|
22
|
+
def connect
|
23
|
+
@token = login
|
24
|
+
end
|
25
|
+
|
26
|
+
def disconnect
|
27
|
+
API.logout
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def login
|
34
|
+
if @email == :token
|
35
|
+
Lita.logger.debug('Logging in using static token')
|
36
|
+
# The password is the token!
|
37
|
+
return @password
|
38
|
+
end
|
39
|
+
|
40
|
+
Lita.logger.debug('Logging in')
|
41
|
+
login_attempts ||= 0
|
42
|
+
|
43
|
+
# First, attempt to get the token from the cache
|
44
|
+
token = @token_cache.token(@email, @password)
|
45
|
+
|
46
|
+
if token
|
47
|
+
Lita.logger.debug('Token successfully obtained from cache!')
|
48
|
+
return token
|
49
|
+
end
|
50
|
+
|
51
|
+
# Login
|
52
|
+
login_response = API.new.login(@email, @password)
|
53
|
+
# raise Discordrb::Errors::HTTPStatusError, login_response.code if login_response.code >= 400
|
54
|
+
|
55
|
+
# Parse response
|
56
|
+
login_response_object = JSON.parse(login_response)
|
57
|
+
# raise Discordrb::Errors::InvalidAuthenticationError unless login_response_object['token']
|
58
|
+
|
59
|
+
Lita.logger.debug('Received token from Discord!')
|
60
|
+
|
61
|
+
# Cache the token
|
62
|
+
@token_cache.store_token(@email, @password, login_response_object['token'])
|
63
|
+
|
64
|
+
login_response_object['token']
|
65
|
+
# rescue Exception => e
|
66
|
+
# response_code = login_response.nil? ? 0 : login_response.code ######## mackmm145
|
67
|
+
# if login_attempts < 100 && (e.inspect.include?('No such host is known.') || response_code == 523)
|
68
|
+
# Lita.logger.debug("Login failed! Reattempting in 5 seconds. #{100 - login_attempts} attempts remaining.")
|
69
|
+
# Lita.logger.debug("Error was: #{e.inspect}")
|
70
|
+
# sleep 5
|
71
|
+
# login_attempts += 1
|
72
|
+
# retry
|
73
|
+
# else
|
74
|
+
# Lita.logger.debug("Login failed permanently after #{login_attempts + 1} attempts")
|
75
|
+
# # Apparently we get a 400 if the password or username is incorrect. In that case, tell the user
|
76
|
+
# Lita.logger.debug("Are you sure you're using the correct username and password?") if e.class == RestClient::BadRequest
|
77
|
+
# # raise $ERROR_INFO
|
78
|
+
# end
|
79
|
+
end
|
80
|
+
|
81
|
+
def logout
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'json'
|
3
|
+
require 'openssl'
|
4
|
+
require 'lita/adapters/discord/api'
|
5
|
+
|
6
|
+
module Lita
|
7
|
+
module Adapters
|
8
|
+
class Discord < Adapter
|
9
|
+
KEYLEN = 32
|
10
|
+
CACHE_PATH = Dir.pwd + '/.discord_token_cache.json'
|
11
|
+
class CachedToken
|
12
|
+
def initialize(data = nil)
|
13
|
+
if data
|
14
|
+
@verify_salt = Base64.decode64(data['verify_salt'])
|
15
|
+
@password_hash = Base64.decode64(data['password_hash'])
|
16
|
+
@encrypt_salt = Base64.decode64(data['encrypt_salt'])
|
17
|
+
@iv = Base64.decode64(data['iv'])
|
18
|
+
@encrypted_token = Base64.decode64(data['encrypted_token'])
|
19
|
+
else
|
20
|
+
generate_salts
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Hash<Symbol => String>] the data representing the token and encryption data, all encrypted and base64-encoded
|
25
|
+
def data
|
26
|
+
{
|
27
|
+
verify_salt: Base64.encode64(@verify_salt),
|
28
|
+
password_hash: Base64.encode64(@password_hash),
|
29
|
+
encrypt_salt: Base64.encode64(@encrypt_salt),
|
30
|
+
iv: Base64.encode64(@iv),
|
31
|
+
encrypted_token: Base64.encode64(@encrypted_token)
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def verify_password(password)
|
36
|
+
hash_password(password) == @password_hash
|
37
|
+
end
|
38
|
+
|
39
|
+
def generate_verify_hash(password)
|
40
|
+
@password_hash = hash_password(password)
|
41
|
+
end
|
42
|
+
|
43
|
+
def obtain_key(password)
|
44
|
+
@key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(password, @encrypt_salt, 300_000, KEYLEN)
|
45
|
+
end
|
46
|
+
|
47
|
+
def generate_salts
|
48
|
+
@verify_salt = OpenSSL::Random.random_bytes(KEYLEN)
|
49
|
+
@encrypt_salt = OpenSSL::Random.random_bytes(KEYLEN)
|
50
|
+
end
|
51
|
+
|
52
|
+
def decrypt_token(password)
|
53
|
+
key = obtain_key(password)
|
54
|
+
decipher = OpenSSL::Cipher::AES256.new(:CBC)
|
55
|
+
decipher.decrypt
|
56
|
+
decipher.key = key
|
57
|
+
decipher.iv = @iv
|
58
|
+
decipher.update(@encrypted_token) + decipher.final
|
59
|
+
end
|
60
|
+
|
61
|
+
def encrypt_token(password, token)
|
62
|
+
key = obtain_key(password)
|
63
|
+
cipher = OpenSSL::Cipher::AES256.new(:CBC)
|
64
|
+
cipher.encrypt
|
65
|
+
cipher.key = key
|
66
|
+
@iv = cipher.random_iv
|
67
|
+
@encrypted_token = cipher.update(token) + cipher.final
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_token(token)
|
71
|
+
API.validate_token(token)
|
72
|
+
end
|
73
|
+
|
74
|
+
def hash_password(password)
|
75
|
+
OpenSSL::PKCS5.pbkdf2_hmac_sha1(password, @verify_salt, 300_000, KEYLEN)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class TokenCache
|
80
|
+
|
81
|
+
def initialize
|
82
|
+
if File.file? CACHE_PATH
|
83
|
+
@data = JSON.parse(File.read(CACHE_PATH))
|
84
|
+
else
|
85
|
+
Lita.logger.debug("Cache file #{CACHE_PATH} not found. Using empty cache")
|
86
|
+
@data = {}
|
87
|
+
end
|
88
|
+
rescue => e
|
89
|
+
Lita.logger.debug('Exception occurred while parsing token cache file:')
|
90
|
+
# I guess start here if stuff is super broken
|
91
|
+
Lita.logger.debug('Continuing with empty cache')
|
92
|
+
@data = {}
|
93
|
+
end
|
94
|
+
|
95
|
+
def token(email, password)
|
96
|
+
if @data[email]
|
97
|
+
begin
|
98
|
+
cached = CachedToken.new(@data[email])
|
99
|
+
if cached.verify_password(password)
|
100
|
+
token = cached.decrypt_token(password)
|
101
|
+
if token
|
102
|
+
begin
|
103
|
+
cached.test_token
|
104
|
+
token
|
105
|
+
rescue => e
|
106
|
+
fail_token('Token cached, verified and decrypted, but rejected by Discord', email)
|
107
|
+
sleep 1
|
108
|
+
nil
|
109
|
+
end
|
110
|
+
else
|
111
|
+
fail_token('Token cached and verified, but decryption failed', email)
|
112
|
+
end
|
113
|
+
else
|
114
|
+
fail_token('Token verification failed', email)
|
115
|
+
end
|
116
|
+
rescue => e
|
117
|
+
fail_token('Token cached but invalid', email)
|
118
|
+
end
|
119
|
+
else
|
120
|
+
fail_token('Token not cached at all')
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def store_token(email, password, token)
|
125
|
+
cached = CachedToken.new
|
126
|
+
cached.generate_verify_hash(password)
|
127
|
+
cached.encrypt_token(password, token)
|
128
|
+
@data[email] = cached.data
|
129
|
+
write_cache
|
130
|
+
end
|
131
|
+
|
132
|
+
def write_cache
|
133
|
+
File.write(CACHE_PATH, @data.to_json)
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
def fail_token(msg, email = nil)
|
139
|
+
Lita.logger.warn("Token not retrieved from cache - #{msg}")
|
140
|
+
@data.delete(email) if email
|
141
|
+
nil
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'lita'
|
2
|
+
require "lita/adapters/discord/client"
|
3
|
+
|
4
|
+
module Lita
|
5
|
+
module Adapters
|
6
|
+
class Discord < Adapter
|
7
|
+
config :email, type: String, required: true
|
8
|
+
config :password, type: String, required: true
|
9
|
+
|
10
|
+
def initialize(robot)
|
11
|
+
super
|
12
|
+
## TIME TO REBUILD THIS SHIZZZZZZ
|
13
|
+
@client = Client.new(config.email, config.password)
|
14
|
+
end
|
15
|
+
|
16
|
+
def run
|
17
|
+
@client.connect
|
18
|
+
end
|
19
|
+
|
20
|
+
def shut_down
|
21
|
+
@client.disconnect
|
22
|
+
end
|
23
|
+
|
24
|
+
# def mention_format(user_id)
|
25
|
+
# "@<#{user_id}>"
|
26
|
+
# end
|
27
|
+
|
28
|
+
# Referenced https://github.com/litaio/lita-slack/blob/master/lib/lita/adapters/slack.rb#L46
|
29
|
+
# Trying to build out basic commands for max plugin compatibility
|
30
|
+
# Update when api is built out
|
31
|
+
# def set_topic(target, topic)
|
32
|
+
|
33
|
+
|
34
|
+
# end
|
35
|
+
|
36
|
+
Lita.register_adapter(:discord, self)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/lita-discord.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
Gem::Specification.new do |spec|
|
2
|
+
spec.name = "lita-discord"
|
3
|
+
spec.version = "0.1.0"
|
4
|
+
spec.authors = ["Kyle Boe"]
|
5
|
+
spec.email = ["ksboe1@gmail.com"]
|
6
|
+
spec.description = "A Discord adapter for Lita"
|
7
|
+
spec.summary = "lita-discord is an adapter for Lita that allows you to use the robot to manage a Discord server."
|
8
|
+
spec.homepage = "https://github.com/kyleboe/lita-discord"
|
9
|
+
spec.license = "MIT"
|
10
|
+
spec.metadata = { "lita_plugin_type" => "adapter" }
|
11
|
+
|
12
|
+
spec.files = `git ls-files`.split($/)
|
13
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
14
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
15
|
+
spec.require_paths = ["lib"]
|
16
|
+
|
17
|
+
spec.add_runtime_dependency "lita", ">= 4.7"
|
18
|
+
|
19
|
+
spec.add_dependency 'rest-client'
|
20
|
+
spec.add_dependency 'faye-websocket'
|
21
|
+
spec.add_dependency 'websocket-client-simple'
|
22
|
+
spec.add_dependency 'eventmachine'
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
25
|
+
spec.add_development_dependency "pry-byebug"
|
26
|
+
spec.add_development_dependency "rake"
|
27
|
+
spec.add_development_dependency "rack-test"
|
28
|
+
spec.add_development_dependency "rspec", ">= 3.0.0"
|
29
|
+
end
|
data/locales/en.yml
ADDED
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,202 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lita-discord
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kyle Boe
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-04-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: lita
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.7'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rest-client
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: faye-websocket
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: websocket-client-simple
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: eventmachine
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: bundler
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.3'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.3'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: pry-byebug
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rake
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rack-test
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rspec
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 3.0.0
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 3.0.0
|
153
|
+
description: A Discord adapter for Lita
|
154
|
+
email:
|
155
|
+
- ksboe1@gmail.com
|
156
|
+
executables: []
|
157
|
+
extensions: []
|
158
|
+
extra_rdoc_files: []
|
159
|
+
files:
|
160
|
+
- ".gitignore"
|
161
|
+
- ".travis.yml"
|
162
|
+
- Gemfile
|
163
|
+
- README.md
|
164
|
+
- Rakefile
|
165
|
+
- lib/lita-discord.rb
|
166
|
+
- lib/lita/adapters/discord.rb
|
167
|
+
- lib/lita/adapters/discord/api.rb
|
168
|
+
- lib/lita/adapters/discord/client.rb
|
169
|
+
- lib/lita/adapters/discord/token_cache.rb
|
170
|
+
- lita-discord.gemspec
|
171
|
+
- locales/en.yml
|
172
|
+
- spec/lita/adapters/discord_spec.rb
|
173
|
+
- spec/spec_helper.rb
|
174
|
+
homepage: https://github.com/kyleboe/lita-discord
|
175
|
+
licenses:
|
176
|
+
- MIT
|
177
|
+
metadata:
|
178
|
+
lita_plugin_type: adapter
|
179
|
+
post_install_message:
|
180
|
+
rdoc_options: []
|
181
|
+
require_paths:
|
182
|
+
- lib
|
183
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
189
|
+
requirements:
|
190
|
+
- - ">="
|
191
|
+
- !ruby/object:Gem::Version
|
192
|
+
version: '0'
|
193
|
+
requirements: []
|
194
|
+
rubyforge_project:
|
195
|
+
rubygems_version: 2.5.1
|
196
|
+
signing_key:
|
197
|
+
specification_version: 4
|
198
|
+
summary: lita-discord is an adapter for Lita that allows you to use the robot to manage
|
199
|
+
a Discord server.
|
200
|
+
test_files:
|
201
|
+
- spec/lita/adapters/discord_spec.rb
|
202
|
+
- spec/spec_helper.rb
|