votifier 0.0.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.
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
19
+
20
+ *~
21
+ #*#
22
+ .#*
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.
@@ -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
@@ -0,0 +1,8 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ end
6
+
7
+ desc "Run tests"
8
+ task :default => :test
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path('../../lib/votifier', __FILE__)
4
+
5
+ public_key_file = File.expand_path('../../config/sample-public.key', __FILE__)
6
+ Votifier::Client.new(public_key_file, "Testing", :username => "linkoer").send
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path('../../lib/votifier', __FILE__)
4
+
5
+ private_key_file = File.expand_path('../../config/sample-private.key', __FILE__)
6
+ Votifier::Server.new(:private_key => private_key_file).listen
@@ -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
@@ -0,0 +1,4 @@
1
+ require File.expand_path('../votifier/vote', __FILE__)
2
+ require File.expand_path('../votifier/server', __FILE__)
3
+ require File.expand_path('../votifier/client', __FILE__)
4
+ require File.expand_path('../votifier/key', __FILE__)
@@ -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
@@ -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,3 @@
1
+ module Votifier
2
+ VERSION = "0.0.1"
3
+ 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
@@ -0,0 +1,8 @@
1
+ require 'test/unit'
2
+ require 'votifier'
3
+
4
+ class VotifierTest < Test::Unit::TestCase
5
+ def test_votifier
6
+ assert true
7
+ end
8
+ end
@@ -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
+