artaius 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/Gemfile +2 -0
- data/LICENSE +19 -0
- data/README.md +19 -0
- data/Rakefile +3 -0
- data/artaius.gemspec +36 -0
- data/bin/artaius +5 -0
- data/config/locales/en.yml +40 -0
- data/config/locales/ru.yml +47 -0
- data/config/plugins/.gitignore +1 -0
- data/db/.gitignore +1 -0
- data/db/migrations/001_create_players.rb +35 -0
- data/lib/artaius.rb +16 -0
- data/lib/artaius/bot.rb +50 -0
- data/lib/artaius/database.rb +36 -0
- data/lib/artaius/models/player.rb +16 -0
- data/lib/artaius/plugins/archivarius.rb +62 -0
- data/lib/artaius/plugins/identify.rb +56 -0
- data/lib/artaius/plugins/mixer.rb +335 -0
- data/lib/artaius/version.rb +3 -0
- data/spec/lib/artaius/bot_spec.rb +54 -0
- data/spec/lib/artaius/plugins/archivarius_spec.rb +59 -0
- data/spec/lib/artaius/plugins/identify_spec.rb +94 -0
- data/spec/lib/artaius/plugins/mixer_spec.rb +199 -0
- data/spec/lib/artaius/version_spec.rb +0 -0
- data/spec/spec_helper.rb +7 -0
- data/tasks/db.rake +15 -0
- data/tasks/environment.rake +3 -0
- data/tasks/test.rake +6 -0
- metadata +213 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (C) 2012 Kyrylo Silin
|
2
|
+
|
3
|
+
This software is provided 'as-is', without any express or implied
|
4
|
+
warranty. In no event will the authors be held liable for any damages
|
5
|
+
arising from the use of this software.
|
6
|
+
|
7
|
+
Permission is granted to anyone to use this software for any purpose,
|
8
|
+
including commercial applications, and to alter it and redistribute it
|
9
|
+
freely, subject to the following restrictions:
|
10
|
+
|
11
|
+
1. The origin of this software must not be misrepresented; you must not
|
12
|
+
claim that you wrote the original software. If you use this software
|
13
|
+
in a product, an acknowledgment in the product documentation would be
|
14
|
+
appreciated but is not required.
|
15
|
+
|
16
|
+
2. Altered source versions must be plainly marked as such, and must not be
|
17
|
+
misrepresented as being the original software.
|
18
|
+
|
19
|
+
3. This notice may not be removed or altered from any source distribution.
|
data/README.md
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
![Artaius][logo]
|
2
|
+
================
|
3
|
+
|
4
|
+
* [https://github.com/kyrylo/artaius/][rkag]
|
5
|
+
|
6
|
+
Description
|
7
|
+
-----------
|
8
|
+
|
9
|
+
Artaius is a [King Arthur's Gold][kag] (KAG) IRC bot. Currently it's not
|
10
|
+
suitable for a public use. Artaius dwells at #kag2d.ru@irc.quakenet.org.
|
11
|
+
|
12
|
+
License
|
13
|
+
-------
|
14
|
+
|
15
|
+
The project uses Zlib License. See LICENSE file for more information.
|
16
|
+
|
17
|
+
[logo]: http://img-fotki.yandex.ru/get/6210/98991937.9/0_7735e_6d44a25d_orig "Artaius logo"
|
18
|
+
[rkag]: https://github.com/kyrylo/artaius/ "Home page"
|
19
|
+
[kag]: http://kag2d.com/
|
data/Rakefile
ADDED
data/artaius.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require './lib/artaius/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = 'artaius'
|
5
|
+
s.version = Artaius::VERSION
|
6
|
+
s.date = Time.now.strftime('%Y-%m-%d')
|
7
|
+
s.summary = "IRC bot serving King Arthur's Gold players."
|
8
|
+
s.author = 'Kyrylo Silin'
|
9
|
+
s.email = 'kyrylosilin@gmail.com'
|
10
|
+
s.homepage = 'https://github.com/kyrylo/artaius'
|
11
|
+
s.license = 'zlib'
|
12
|
+
|
13
|
+
s.require_path = 'lib'
|
14
|
+
s.files = `git ls-files`.split "\n"
|
15
|
+
s.test_files = `git ls-files -- spec`.split "\n"
|
16
|
+
|
17
|
+
s.extra_rdoc_files = %W{README.md LICENSE}
|
18
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
19
|
+
|
20
|
+
s.add_runtime_dependency 'cinch', '~>2.0'
|
21
|
+
s.add_runtime_dependency 'kag', '0.0.1'
|
22
|
+
s.add_runtime_dependency 'r18n-desktop', '>=0.4.14'
|
23
|
+
s.add_runtime_dependency 'sequel', '>=3.34.1'
|
24
|
+
s.add_runtime_dependency 'sqlite3', '>=1.3.6'
|
25
|
+
|
26
|
+
s.add_development_dependency 'rake'
|
27
|
+
s.add_development_dependency 'minitest', '>=2.12.1'
|
28
|
+
s.add_development_dependency 'fivemat', '>=1.0.0'
|
29
|
+
|
30
|
+
s.required_ruby_version = '~>1.9'
|
31
|
+
|
32
|
+
s.description = <<description
|
33
|
+
Artaius is an IRC (Internet Relay Chat) bot for KAG (King Arthur's Gold)
|
34
|
+
game. It cannot everything for the time being.
|
35
|
+
description
|
36
|
+
end
|
data/bin/artaius
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
---
|
2
|
+
identify:
|
3
|
+
send_challenge: "Identifying with Q, using CHALLENGEAUTH"
|
4
|
+
challenge: "[CHALLENGE received] Challenge: %1"
|
5
|
+
|
6
|
+
mixer:
|
7
|
+
players: "Players: %1."
|
8
|
+
need_players: !!pl
|
9
|
+
1: "Need 1 more player to start the game."
|
10
|
+
n: "Need %1 more players to start the game"
|
11
|
+
cancel: "%1, you are not in the game anymore."
|
12
|
+
last_left: "The last player has left the game. The game is cancelled."
|
13
|
+
new_initiator: "New game inititator is %1."
|
14
|
+
roster: "Roster: %1."
|
15
|
+
n_slots_added: "%1 slots have been added. %2"
|
16
|
+
slot_added: "Slot added. %1"
|
17
|
+
n_slots_removed: "%1 slots have been removed. %2"
|
18
|
+
slot_removed: "Slot removed. %1"
|
19
|
+
slot_stats: "Slots: %1/%2."
|
20
|
+
blue_team: "Blue team: %1."
|
21
|
+
red_team: "Red team: %1."
|
22
|
+
glhf: "Good luck & have a good fun!"
|
23
|
+
slots_overall: "Total number of slots are %1."
|
24
|
+
game_cancelled: "The game has been cancelled due to shortage of players."
|
25
|
+
m:
|
26
|
+
game: "game"
|
27
|
+
play: "play"
|
28
|
+
cancel: "cancel"
|
29
|
+
roster: "roster"
|
30
|
+
start: "start"
|
31
|
+
slot: "slot"
|
32
|
+
slots: "slots"
|
33
|
+
|
34
|
+
archivarius:
|
35
|
+
exists: "%1, you are already registered and bonded your KAG account and IRC authname (%2)."
|
36
|
+
not_found: "Player %1 does not exist. Did you make a typing error?"
|
37
|
+
authname_required: "In order to bond your KAG account and IRC authname, you need to authorize on this server or register your nickname"
|
38
|
+
success: "Yay, registration complete! Enjoy KAG ;-)"
|
39
|
+
m:
|
40
|
+
reg: "reg"
|
@@ -0,0 +1,47 @@
|
|
1
|
+
---
|
2
|
+
identify:
|
3
|
+
send_challenge: "Идентифицируюсь с помощью Q, используя CHALLENGEAUTH"
|
4
|
+
challenge: "[CHALLENGE получен] Challenge: %1"
|
5
|
+
|
6
|
+
mixer:
|
7
|
+
players: "Игроки: %1."
|
8
|
+
need_players: !!pl
|
9
|
+
1: "Для начала игры нужен еще 1 игрок."
|
10
|
+
2: "Для начала игры нужно еще %1 игрока."
|
11
|
+
n: "Для начала игры нужно еще %1 игроков."
|
12
|
+
cancel: "%1, вы вышли из игры."
|
13
|
+
last_left: "Последний игрок покинул игру. Игра отменена."
|
14
|
+
new_initiator: "%1 - новый инициатор игры."
|
15
|
+
roster: "Состав: %1."
|
16
|
+
n_slots_added: !!pl
|
17
|
+
1: "Добавлен 1 слот. %2"
|
18
|
+
2: "Добавлено %1 слота. %2"
|
19
|
+
n: "Добавлено %1 слотов. %2"
|
20
|
+
slot_added: "Слот добавлен. %1"
|
21
|
+
n_slots_removed: !!pl
|
22
|
+
1: "Убран 1 слот. %2"
|
23
|
+
2: "Убрано %1 слота. %2"
|
24
|
+
n: "Убрано %1 слотов. %2"
|
25
|
+
slot_removed: "Слот убран. %1"
|
26
|
+
slot_stats: "Слоты: %1/%2."
|
27
|
+
blue_team: "Команда синих: %1."
|
28
|
+
red_team: "Команда красных: %1."
|
29
|
+
glhf: "Удачи. Победит сильнейший!"
|
30
|
+
slots_overall: "Общее количество слотов: %1."
|
31
|
+
game_cancelled: "Игра была отменена из-за нехватки игроков."
|
32
|
+
m:
|
33
|
+
game: "игра"
|
34
|
+
play: "играть"
|
35
|
+
cancel: "отмена"
|
36
|
+
roster: "состав"
|
37
|
+
start: "старт"
|
38
|
+
slot: "слот"
|
39
|
+
slots: "слоты"
|
40
|
+
|
41
|
+
archivarius:
|
42
|
+
exists: "%1, вы уже привязали свой аккаунт в КАГ-е к вашему логину в ИРЦ (%2)."
|
43
|
+
not_found: "Игрок %1 не существует. Опечатались?"
|
44
|
+
authname_required: "Чтобы связать ваш аккаунт в КАГ-е и ИРЦ логин, вы должны авторизироваться на этом сервере или зарегистрировать свой ник."
|
45
|
+
success: "Ура, регистрация завершена! Наслаждайтеь КАГ-ом ;-)"
|
46
|
+
m:
|
47
|
+
reg: "регь"
|
@@ -0,0 +1 @@
|
|
1
|
+
identify.yml
|
data/db/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.db
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Create initial schema for the table of registered players.
|
2
|
+
#
|
3
|
+
# Note, that while KAG's maximum length of nicknames is equal to 20,
|
4
|
+
# QuakeNet allows only 15 letters (NICKLEN field in the ISUPPORT message).
|
5
|
+
#
|
6
|
+
# +--------------+--------------------------------------+
|
7
|
+
# | Field | Description |
|
8
|
+
# +--------------+--------------------------------------+
|
9
|
+
# | id | Player id number. |
|
10
|
+
# | irc_authname | IRC authname of player. |
|
11
|
+
# | kag_nick | King Arthur's Gold in-game nickname. |
|
12
|
+
# | role | Role of the player [1] |
|
13
|
+
# | premium | Account type (true if premium). |
|
14
|
+
# +--------------+--------------------------------------+
|
15
|
+
#
|
16
|
+
# [1] Roles:
|
17
|
+
# 0: Normal player account
|
18
|
+
# 1: KAG dev/team member
|
19
|
+
# 2: KAG Guard.
|
20
|
+
# 4: KAG team member ("admin" level, more or less the same as type 1)
|
21
|
+
# 5: Possibly a tester, but most testers are not currently flagged
|
22
|
+
#
|
23
|
+
Sequel.migration do
|
24
|
+
change do
|
25
|
+
create_table :players do
|
26
|
+
primary_key :id
|
27
|
+
String :irc_authname, :unique => true, :size => 15, :null => false
|
28
|
+
String :kag_nick, :unique => true, :size => 20, :null => false
|
29
|
+
Fixnum :role, :null => false
|
30
|
+
FalseClass :premium, :null => false
|
31
|
+
DateTime :created_at
|
32
|
+
DateTime :updated_at
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/artaius.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'cinch'
|
2
|
+
require 'kag'
|
3
|
+
require 'yaml'
|
4
|
+
require 'r18n-desktop'
|
5
|
+
require 'sequel'
|
6
|
+
require 'sequel/extensions/migration'
|
7
|
+
|
8
|
+
require_relative 'artaius/bot'
|
9
|
+
require_relative 'artaius/version'
|
10
|
+
|
11
|
+
require_relative 'artaius/database'
|
12
|
+
require_relative 'artaius/models/player'
|
13
|
+
|
14
|
+
require_relative 'artaius/plugins/identify'
|
15
|
+
require_relative 'artaius/plugins/mixer'
|
16
|
+
require_relative 'artaius/plugins/archivarius'
|
data/lib/artaius/bot.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
module Artaius
|
2
|
+
|
3
|
+
# Internal: Turn the bot into a polyglot.
|
4
|
+
I18n = R18n.from_env('config/locales/', :ru)
|
5
|
+
|
6
|
+
class Bot < Cinch::Bot
|
7
|
+
|
8
|
+
# Internal: Name.
|
9
|
+
FIRST_NAME = 'Artaius'
|
10
|
+
|
11
|
+
# Internal: Surname.
|
12
|
+
SECOND_NAME = 'Lucius'
|
13
|
+
|
14
|
+
# Internal: IRC server to join.
|
15
|
+
SERVER = 'irc.quakenet.org'
|
16
|
+
|
17
|
+
# Internal: Port of IRC server.
|
18
|
+
PORT = 6667
|
19
|
+
|
20
|
+
# Internal: Channels, that bot should be present on..
|
21
|
+
CHANNELS = ['#kag2d.ru']
|
22
|
+
|
23
|
+
def initialize
|
24
|
+
super
|
25
|
+
|
26
|
+
# Bot configuration.
|
27
|
+
configure do |c|
|
28
|
+
c.nick = FIRST_NAME
|
29
|
+
c.realname = "#{FIRST_NAME} #{SECOND_NAME}"
|
30
|
+
c.user = "#{FIRST_NAME} #{SECOND_NAME}"
|
31
|
+
c.server = SERVER
|
32
|
+
c.port = PORT
|
33
|
+
c.channels = CHANNELS
|
34
|
+
c.plugins.plugins = [
|
35
|
+
Artaius::Plugins::Identify,
|
36
|
+
Artaius::Plugins::Mixer,
|
37
|
+
Artaius::Plugins::Archivarius
|
38
|
+
]
|
39
|
+
|
40
|
+
# Set up plugins to be used.
|
41
|
+
c.plugins.options[Artaius::Plugins::Identify] = {
|
42
|
+
:username => FIRST_NAME,
|
43
|
+
:password => Psych.load_file('config/plugins/identify.yml')[:password]
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Artaius
|
2
|
+
# Internal: Connect Artaius to the database via Sequel interface.
|
3
|
+
Database = Sequel.sqlite(File.join(File.expand_path('db'), 'artaius.db'))
|
4
|
+
|
5
|
+
class << Database
|
6
|
+
|
7
|
+
# Internal: Migrate database from older version to the new one or vice
|
8
|
+
# versa. Without given arguments, migrate database to the latest version
|
9
|
+
# available.
|
10
|
+
#
|
11
|
+
# to - The Integer, describes version, to version till which migrations
|
12
|
+
# should be applied (default: nil).
|
13
|
+
# from - The Integer, describes version, from which migration should start
|
14
|
+
# its work (default: nil).
|
15
|
+
#
|
16
|
+
# Returns nothing.
|
17
|
+
def migrate(to = nil, from = nil)
|
18
|
+
migrations = File.join(File.expand_path('db'), 'migrations')
|
19
|
+
if to == 0 && from == 0
|
20
|
+
Sequel::Migrator.apply(self, migrations)
|
21
|
+
else
|
22
|
+
Sequel::Migrator.apply(self, migrations, to, from)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Internal: Rollback current version of database to the previous one. This
|
27
|
+
# method returns database exactly one step back.
|
28
|
+
#
|
29
|
+
# Returns nothing
|
30
|
+
def rollback
|
31
|
+
current_version = self[:schema_info].first[:version]
|
32
|
+
migrate(current_version.pred)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Artaius
|
2
|
+
# Internal: Represents KAG player.
|
3
|
+
class Player < Sequel::Model(:players)
|
4
|
+
plugin :timestamps, :update_on_create => true
|
5
|
+
|
6
|
+
# Internal: Check database for given authname.
|
7
|
+
#
|
8
|
+
# irc_authname - The String, represents IRC authname of the player.
|
9
|
+
#
|
10
|
+
# Returns true if the given authname is in database or false otherwise.
|
11
|
+
def self.exists?(irc_authname)
|
12
|
+
filter(:irc_authname => irc_authname).select(:irc_authname).any?
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Artaius
|
2
|
+
module Plugins
|
3
|
+
# The plugin handles registration of users. The aim of the plugin is to
|
4
|
+
# associate KAG account and IRC authname together.
|
5
|
+
class Archivarius
|
6
|
+
include Cinch::Plugin
|
7
|
+
|
8
|
+
set react_on: :private
|
9
|
+
|
10
|
+
match /#{I18n.archivarius.m.reg} (\w{3,20})$/,
|
11
|
+
method: :sign_up,
|
12
|
+
use_suffix: false
|
13
|
+
|
14
|
+
# Internal: Sign up a new player with some restrictions: it won't sign up
|
15
|
+
# neither already registered players, nor players, that doesn't have IRC
|
16
|
+
# autname, nor nonexistent KAG players.
|
17
|
+
#
|
18
|
+
# m - The recieved message.
|
19
|
+
# kag_nick - The String, represents KAG nickname to be associated with
|
20
|
+
# caller's IRC authanme.
|
21
|
+
#
|
22
|
+
# Returns nothing.
|
23
|
+
def sign_up(m, kag_nick)
|
24
|
+
authname = m.user.authname
|
25
|
+
nick = m.user.nick
|
26
|
+
|
27
|
+
if authname.nil?
|
28
|
+
m.reply I18n.archivarius.authname_required and return
|
29
|
+
end
|
30
|
+
|
31
|
+
if already_exists?(authname)
|
32
|
+
m.reply I18n.archivarius.exists(nick, authname) and return
|
33
|
+
end
|
34
|
+
|
35
|
+
player = KAG::Player.new(kag_nick)
|
36
|
+
|
37
|
+
if player.info['statusMessage'] == 'Player not found'
|
38
|
+
m.reply I18n.archivarius.not_found(kag_nick) and return
|
39
|
+
end
|
40
|
+
|
41
|
+
Player.create(
|
42
|
+
:irc_authname => authname,
|
43
|
+
:kag_nick => player.username,
|
44
|
+
:role => player.role,
|
45
|
+
:premium => player.gold?
|
46
|
+
)
|
47
|
+
|
48
|
+
m.reply I18n.archivarius.success
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
# Internal: Ask database for whether the IRC authname is in it or not.
|
54
|
+
#
|
55
|
+
# Returns true, if the IRC authname is there of false otherwise.
|
56
|
+
def already_exists?(irc_authname)
|
57
|
+
Player.exists?(irc_authname)
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
|
3
|
+
module Artaius
|
4
|
+
module Plugins
|
5
|
+
# The plugin handles authentication via CHALLENGEAUTH. It requires two
|
6
|
+
# parameters: username and password of the bot. For details go here:
|
7
|
+
# http://www.quakenet.org/development/challengeauth/
|
8
|
+
class Identify
|
9
|
+
include Cinch::Plugin
|
10
|
+
|
11
|
+
set :required_options, [:username, :password]
|
12
|
+
|
13
|
+
# Internal: Q bot of QuakeNet. Nine times out of ten you write him a PM.
|
14
|
+
Q = 'Q@CServe.quakenet.org'
|
15
|
+
|
16
|
+
|
17
|
+
listen_to :connect,
|
18
|
+
method: :send_challenge
|
19
|
+
|
20
|
+
# Internal: Identify a bot with Q.
|
21
|
+
#
|
22
|
+
# Returns nothing.
|
23
|
+
def send_challenge(m)
|
24
|
+
debug I18n.identify.send_challenge
|
25
|
+
User(Q).privmsg('CHALLENGE')
|
26
|
+
end
|
27
|
+
|
28
|
+
match /^CHALLENGE (.+?) (.+)$/,
|
29
|
+
method: :challengeauth,
|
30
|
+
use_prefix: false,
|
31
|
+
use_suffix: false,
|
32
|
+
react_on: :notice
|
33
|
+
|
34
|
+
# Internal: Authenticate bot with safe CHALLENGEAUTH method.
|
35
|
+
#
|
36
|
+
# m - The recieved message.
|
37
|
+
# challenge - The CHALLENGE parameter, given by Q bot.
|
38
|
+
#
|
39
|
+
# Returns nothing.
|
40
|
+
def challengeauth(m, challenge)
|
41
|
+
# Q is the only trusted user.
|
42
|
+
return unless m.user && m.user.nick == 'Q'
|
43
|
+
|
44
|
+
debug I18n.identify.challenge(challenge)
|
45
|
+
|
46
|
+
username = config[:username].irc_downcase(:rfc1459)
|
47
|
+
password = config[:password][0, 10]
|
48
|
+
|
49
|
+
sha256 = OpenSSL::Digest::SHA256.new
|
50
|
+
key = sha256.hexdigest("#{ username }:#{ sha256.hexdigest(password) }")
|
51
|
+
response = OpenSSL::HMAC.hexdigest('SHA256', key, challenge)
|
52
|
+
User(Q).privmsg("CHALLENGEAUTH #{ username } #{ response } HMAC-SHA-256")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|