votifier 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +22 -0
- data/LICENSE +20 -0
- data/README.md +38 -0
- data/Rakefile +8 -0
- data/bin/votifier-client +6 -0
- data/bin/votifier-server +6 -0
- data/config/sample-private.key +1 -0
- data/config/sample-public.key +1 -0
- data/lib/votifier.rb +4 -0
- data/lib/votifier/client.rb +81 -0
- data/lib/votifier/key.rb +51 -0
- data/lib/votifier/server.rb +64 -0
- data/lib/votifier/version.rb +3 -0
- data/lib/votifier/vote.rb +27 -0
- data/test/test_votifer.rb +8 -0
- data/votifier.gemspec +18 -0
- metadata +81 -0
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 pr4xt3roy
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# Votifier Gem
|
2
|
+
|
3
|
+
Ruby Gem for a Votifier Server and Client for Minecraft
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
For a manual installation, type this on your console:
|
8
|
+
|
9
|
+
$ gem install votifier
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
require 'votifier'
|
14
|
+
Votifier::Client.new(public_key_file, "MyMinecraftServerList.info", :username => "Notch").send
|
15
|
+
|
16
|
+
If you have the player's IP addess and the timestamp, you can pass them
|
17
|
+
|
18
|
+
require 'votifier'
|
19
|
+
Votifier::Client.new(public_key_file, "MyMinecraftServerList.info", :username => "Notch", :ip_address => @ip_address, :timestamp => @timestamp).send
|
20
|
+
|
21
|
+
For the server:
|
22
|
+
|
23
|
+
require 'votifier'
|
24
|
+
Votifier::Server.new(:private_key => private_key_file).listen
|
25
|
+
|
26
|
+
## TODO
|
27
|
+
|
28
|
+
* Unit Tests
|
29
|
+
* Support .pem, .key keys or string keys.
|
30
|
+
* The username, ip and timestamp should be passed to Votifier::Client#send instead of the contructor
|
31
|
+
|
32
|
+
## Contributing
|
33
|
+
|
34
|
+
1. Fork it
|
35
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
36
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
37
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
38
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/votifier-client
ADDED
data/bin/votifier-server
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
MIIEogIBAAKCAQEAqEyG+i/SNvCRsvM4jt3tm2fresIPCBpfU/5j0Pq4i2IjPzX0YQqHmBqrKqzIpMTgj9ITrxJ4v3FO8WHjjArEAJhYPc26w9cniVaXAFavQX07q0wZ9DJRdei6lchd5ecLQ5J90TrR4BpwxFGtw55vOpPElQi2jG1crr3fIqVspMtqPUXYesmD5Ymoace0ycPs46yS6ItWwgbPBaryeimUG0ErHoYV2aWjfP/FHnawU2n3fNWy3ZD9e7AWSwdFxYnPSZ3R9+V/YSlyYX/ls0k8SC/L9xB63rh8ifg66sgN5hlxbMIIwX2trGueeDYbYkiL499Hzj4KPfWT1L+t3a8HdwIDAQABAoIBAHcXSAAr7L3xt7gAggoeoq9wduI0Bfz+5GwEPE+5yvLerABjxp0QnWiVnn+hKo3lvt4mksU09frKTElksmb7izy8kNyTAtDoI9L8UffsXzGhU6LgRBFXtesQl0+8LC2uM3tKYvu2eqLxMtDI14PwTdcOj3HCa6KtFIOWWhojIuDs5f45V64pBqrC0a4Alcppzjb1rJTsg7FXp1EIwx+WEc+sV34y9dwogokQrpU7mD2LdTOT4jcQ/NnpSMXMGpbi+CtynOhM6G4vwy2hLaV5dENwchlyWYXnDPuDEZK6/+1WWWJnHV1mhKDK1PEvia7JRxWNlZeNrDKMpDgoDg5BuSECgYEA2wU7euS4ekugZ1XHakrno55phdS39jS4YaB9RoheAt2IusbYK309q8PtcsDt8mtT9F3ji5C66YJsvuht7Dfb4HXVvpPkKU8eN3wOzI3zBEZ0HEmbKf6AKTE4msjd3/zAeMGr2KSllJbomqrQBieMDdffRZ8qyo10WENlH5miw0cCgYEAxLbyygzV6r0mRxtw4H8SjrjAPyA9eOhwDB07peGi7kv6dEUYhu4gcaUPQSMigqV0ADNTed8ueq2HzJ4V5nqkg97sK6Q00yLOxUkwq5aKD4Fq1vctotawX9SOPyjzKwtu8BXzJDESIyrxuWgDB2ZGQtfvaI+guOVHakwq1+SJ0lECgYAtmchJjQdvxwEtoqlzUwcphNj5mVF3/IALK4wJvGi+dft6z93AKEJH2fI9OzgPihMfxNCUhVy1M4eKs//296Za9I29MTOG+kcTTEwUgNWBJV4VaanZs3hhmzLq3zl64jf8rG4oHBexeT4Svc+0CFXbp/9/kmUpaQw5OEb8rlM6DwKBgHUNe9kY3C2LEfzb6kXbt1ovu02UzJ9miE3dE0I4ym/LzCNlfhvEFJArLLGQy5c8BpOb9v8c+5ZKLfVm2BdGQSCrBJNPaZN9MdaZH5nqwQpK8x0pBgHQiDDt1RrmLhQeAIxiM0UE4gsFIcM2jh7YD9T0kuQAGx4KaH1rB09iEVSRAoGALrDquzyGNU75h9X46wFibbLbRs5H/pjwFn2kXjdfCatrPRYhCDBp2cM2jRLt3xua/Icg8b3tzAEcyabIuieH0tTI+Cc+IzrJeLspHHOvgqa1voJEwnkmsCorwh4umV+5yCtFWuVQNNpbU7Kk50FhlSaS75JQsrxmkUJaQ7+9Lt0=
|
@@ -0,0 +1 @@
|
|
1
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqEyG+i/SNvCRsvM4jt3tm2fresIPCBpfU/5j0Pq4i2IjPzX0YQqHmBqrKqzIpMTgj9ITrxJ4v3FO8WHjjArEAJhYPc26w9cniVaXAFavQX07q0wZ9DJRdei6lchd5ecLQ5J90TrR4BpwxFGtw55vOpPElQi2jG1crr3fIqVspMtqPUXYesmD5Ymoace0ycPs46yS6ItWwgbPBaryeimUG0ErHoYV2aWjfP/FHnawU2n3fNWy3ZD9e7AWSwdFxYnPSZ3R9+V/YSlyYX/ls0k8SC/L9xB63rh8ifg66sgN5hlxbMIIwX2trGueeDYbYkiL499Hzj4KPfWT1L+t3a8HdwIDAQAB
|
data/lib/votifier.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'socket' # Sockets are in standard library
|
2
|
+
|
3
|
+
module Votifier
|
4
|
+
class Client
|
5
|
+
|
6
|
+
attr_reader :public_key, :service_name
|
7
|
+
attr_accessor :username, :ip_address, :timestamp
|
8
|
+
|
9
|
+
def initialize(public_key_file, service_name, opts = {})
|
10
|
+
init_public_key(public_key_file)
|
11
|
+
@service_name = service_name
|
12
|
+
@username = opts.fetch(:username, nil)
|
13
|
+
@ip_address = opts.fetch(:ip_address, detect_ip_address)
|
14
|
+
@timestamp = opts.fetch(:timestamp, Time.now.to_i)
|
15
|
+
end
|
16
|
+
|
17
|
+
def init_public_key(public_key_file)
|
18
|
+
@public_key = Votifer::Key.from_public_key_file(public_key_file)
|
19
|
+
end
|
20
|
+
|
21
|
+
def detect_ip_address
|
22
|
+
remote_ip = ENV['HTTP_X_FORWARDED_FOR'] || ENV['REMOTE_ADDR'] || my_best_ip_address
|
23
|
+
remote_ip = remote_ip.ip_address if remote_ip.respond_to?(:ip_address)
|
24
|
+
remote_ip = remote_ip.scan(/[\d.]+/).first
|
25
|
+
end
|
26
|
+
|
27
|
+
def my_best_ip_address
|
28
|
+
my_first_public_ipv4 || my_first_private_ipv4
|
29
|
+
end
|
30
|
+
|
31
|
+
def my_first_public_ipv4
|
32
|
+
ips.detect{|intf| intf.ipv4? and !intf.ipv4_loopback? and !intf.ipv4_multicast? and !intf.ipv4_private?}
|
33
|
+
end
|
34
|
+
|
35
|
+
def my_first_private_ipv4
|
36
|
+
ips.detect{|intf| intf.ipv4_private?}
|
37
|
+
end
|
38
|
+
|
39
|
+
def ips
|
40
|
+
@ips ||= Socket.ip_address_list
|
41
|
+
end
|
42
|
+
|
43
|
+
def send
|
44
|
+
validate!
|
45
|
+
votifier_string = to_a.join("\n")
|
46
|
+
encrypted = encrypt(votifier_string)
|
47
|
+
send_to_server(encrypted)
|
48
|
+
end
|
49
|
+
|
50
|
+
def validate!
|
51
|
+
raise 'Usename must be present' unless !username.nil?
|
52
|
+
end
|
53
|
+
|
54
|
+
def encrypt(votifier_string)
|
55
|
+
encrypted = public_key.public_encrypt(votifier_string)
|
56
|
+
raise "Error encrypting, invalid size: #{encrypted.bytesize}" unless encrypted.bytesize == 256
|
57
|
+
encrypted
|
58
|
+
end
|
59
|
+
|
60
|
+
def send_to_server(encrypted)
|
61
|
+
hostname = 'localhost'
|
62
|
+
port = 8193
|
63
|
+
|
64
|
+
s = TCPSocket.open(hostname, port)
|
65
|
+
|
66
|
+
s.print encrypted
|
67
|
+
s.close
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_a
|
71
|
+
[
|
72
|
+
"VOTE",
|
73
|
+
service_name,
|
74
|
+
username,
|
75
|
+
ip_address,
|
76
|
+
timestamp
|
77
|
+
]
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
data/lib/votifier/key.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'openssl'
|
3
|
+
module Votifer
|
4
|
+
class Key
|
5
|
+
|
6
|
+
def initialize(pem_key_content)
|
7
|
+
@key = OpenSSL::PKey::RSA.new(pem_key_content)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.from_pem_key_file(key_file)
|
11
|
+
key_content = File.read(key_file)
|
12
|
+
self.from_perm_key_content(key_content)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.from_public_key_file(key_file)
|
16
|
+
self.from_key_file(key_file, :public)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.from_key_file(key_file, type = :private)
|
20
|
+
key_content = File.read(key_file)
|
21
|
+
self.from_key_content(key_content, type)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.from_key_content(key_content, type = :private)
|
25
|
+
pem_key_content = convert_to_pem_format(key_content, type)
|
26
|
+
from_pem_key_content(pem_key_content)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.from_pem_key_content(pem_key_content)
|
30
|
+
key = self.new(pem_key_content)
|
31
|
+
key
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.convert_to_pem_format(key_content, type = :private)
|
35
|
+
key_headers = {
|
36
|
+
:private => "RSA PRIVATE",
|
37
|
+
:public => "PUBLIC"
|
38
|
+
}
|
39
|
+
header = key_headers[type]
|
40
|
+
wrapped_key_content = key_content.scan(/.{1,65}/).join("\n")
|
41
|
+
pem_key_content = "-----BEGIN #{header} KEY-----\n" +
|
42
|
+
wrapped_key_content + "\n" +
|
43
|
+
"-----END #{header} KEY-----"
|
44
|
+
pem_key_content
|
45
|
+
end
|
46
|
+
|
47
|
+
extend Forwardable
|
48
|
+
def_delegators :@key, :private_decrypt, :public_encrypt
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'socket' # Get sockets from stdlib
|
2
|
+
module Votifier
|
3
|
+
class Server
|
4
|
+
|
5
|
+
attr_reader :private_key
|
6
|
+
|
7
|
+
def initialize(opts)
|
8
|
+
raise ':private_key options is required' unless opts.key?(:private_key)
|
9
|
+
init_private_key(opts[:private_key])
|
10
|
+
end
|
11
|
+
|
12
|
+
def init_private_key(private_key_file)
|
13
|
+
@private_key = Votifer::Key.from_key_file(private_key_file)
|
14
|
+
end
|
15
|
+
|
16
|
+
def listen
|
17
|
+
server = TCPServer.open(8193) # Socket to listen on port
|
18
|
+
loop { # Servers run forever
|
19
|
+
Thread.start(server.accept) do |client| # Wait for a client to connect
|
20
|
+
handle_connection(client)
|
21
|
+
end
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def handle_connection(client)
|
26
|
+
lines = ""
|
27
|
+
while line = client.gets
|
28
|
+
lines += line
|
29
|
+
end
|
30
|
+
begin
|
31
|
+
vote_info = parse_content(lines)
|
32
|
+
vote = Vote.from_array(vote_info)
|
33
|
+
puts vote.to_h
|
34
|
+
client.close # Disconnect from the client
|
35
|
+
rescue => e
|
36
|
+
puts e.inspect
|
37
|
+
puts e.backtrace
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def parse_content(content)
|
42
|
+
raise Error::InvalidVotePacket, "Must be 256 bytes: is #{content.bytesize}" unless content.bytesize == 256
|
43
|
+
vote_info_string = decrypt(content)
|
44
|
+
raise Error::InvalidVotePacket, 'Must contains newline characters' unless vote_info_string.match(/\n/)
|
45
|
+
vote_info = vote_info_string.split("\n")
|
46
|
+
raise Error::InvalidVotePacket, 'Must contain 5 elements or more' unless vote_info.size >= 5
|
47
|
+
raise Error::InvalidVotePacket, 'Invalid opcode: must be VOTE' unless vote_info[0] == "VOTE"
|
48
|
+
vote_info
|
49
|
+
end
|
50
|
+
|
51
|
+
def decrypt(encrypted_string)
|
52
|
+
string = private_key.private_decrypt(encrypted_string)
|
53
|
+
string
|
54
|
+
end
|
55
|
+
|
56
|
+
class Error
|
57
|
+
class InvalidVotePacket < StandardError
|
58
|
+
def initialize(str)
|
59
|
+
super("Invalid Vote Packet: #{str}")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Votifier
|
2
|
+
class Vote
|
3
|
+
attr_reader :service_name, :username, :ip_address, :timestamp
|
4
|
+
|
5
|
+
def initialize(service_name, username, ip_address, timestamp)
|
6
|
+
@service_name = service_name
|
7
|
+
@username = username
|
8
|
+
@ip_address = ip_address
|
9
|
+
@timestamp = timestamp
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.from_array(vote_info)
|
13
|
+
opcode, service_name, username, ip_address, timestamp, empty_space = vote_info
|
14
|
+
vote = Vote.new(service_name, username, ip_address, timestamp)
|
15
|
+
vote
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_h
|
19
|
+
{
|
20
|
+
:service_name => service_name,
|
21
|
+
:username => username,
|
22
|
+
:ip_address => ip_address,
|
23
|
+
:timestamp => timestamp
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/votifier.gemspec
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/votifier/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.name = 'votifier'
|
6
|
+
gem.summary = %q{Votifier Server and Client for Minecraft}
|
7
|
+
gem.description = %q{This allows you to accept Votifier connections OR send them to a Minecraft Server.}
|
8
|
+
gem.authors = ["Pr4xt3roy"]
|
9
|
+
gem.email = %W(pr4xt3roy@capricatown.net)
|
10
|
+
gem.homepage = 'https://github.com/pr4xt3roy/votifier-gem'
|
11
|
+
|
12
|
+
gem.files = `git ls-files`.split($\)
|
13
|
+
gem.license = 'MIT'
|
14
|
+
gem.require_paths = ["lib"]
|
15
|
+
|
16
|
+
gem.version = Votifier::VERSION
|
17
|
+
gem.date = '2013-09-08'
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: votifier
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Pr4xt3roy
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2013-09-08 00:00:00 Z
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: This allows you to accept Votifier connections OR send them to a Minecraft Server.
|
22
|
+
email:
|
23
|
+
- pr4xt3roy@capricatown.net
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- .gitignore
|
32
|
+
- LICENSE
|
33
|
+
- README.md
|
34
|
+
- Rakefile
|
35
|
+
- bin/votifier-client
|
36
|
+
- bin/votifier-server
|
37
|
+
- config/sample-private.key
|
38
|
+
- config/sample-public.key
|
39
|
+
- lib/votifier.rb
|
40
|
+
- lib/votifier/client.rb
|
41
|
+
- lib/votifier/key.rb
|
42
|
+
- lib/votifier/server.rb
|
43
|
+
- lib/votifier/version.rb
|
44
|
+
- lib/votifier/vote.rb
|
45
|
+
- test/test_votifer.rb
|
46
|
+
- votifier.gemspec
|
47
|
+
homepage: https://github.com/pr4xt3roy/votifier-gem
|
48
|
+
licenses:
|
49
|
+
- MIT
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
hash: 3
|
61
|
+
segments:
|
62
|
+
- 0
|
63
|
+
version: "0"
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
hash: 3
|
70
|
+
segments:
|
71
|
+
- 0
|
72
|
+
version: "0"
|
73
|
+
requirements: []
|
74
|
+
|
75
|
+
rubyforge_project:
|
76
|
+
rubygems_version: 1.8.15
|
77
|
+
signing_key:
|
78
|
+
specification_version: 3
|
79
|
+
summary: Votifier Server and Client for Minecraft
|
80
|
+
test_files: []
|
81
|
+
|