gamekey 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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.idea/.name +1 -0
- data/.idea/.rakeTasks +7 -0
- data/.idea/codeStyleSettings.xml +13 -0
- data/.idea/encodings.xml +6 -0
- data/.idea/gamekey.iml +97 -0
- data/.idea/misc.xml +14 -0
- data/.idea/modules.xml +8 -0
- data/.idea/vcs.xml +6 -0
- data/.idea/workspace.xml +946 -0
- data/Dockerfile +13 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +133 -0
- data/Rakefile +1 -0
- data/bin/gamekey +232 -0
- data/gamekey.gemspec +32 -0
- data/lib/auth.rb +14 -0
- data/lib/defaults.rb +47 -0
- data/lib/gamekey.rb +632 -0
- data/lib/gamekey/version.rb +3 -0
- data/lib/reference.rb +854 -0
- data/projectFilesBackup/.idea/gamekey.iml +8 -0
- metadata +167 -0
data/Dockerfile
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Nane Kratzke
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
# Gamekey
|
2
|
+
|
3
|
+
A reference REST service to store game states.
|
4
|
+
This service is intended as a reference service used in Webtechnology Projects
|
5
|
+
at Lübeck University of Applied Sciences.
|
6
|
+
|
7
|
+
## Installation via Docker (1st Option)
|
8
|
+
|
9
|
+
The most easiest way to deploy the gamekey reference service is via Docker.
|
10
|
+
You will find here [Docker](https://docs.docker.com/engine/installation/) installation instructions for various
|
11
|
+
operating systems.
|
12
|
+
|
13
|
+
After installing docker you can fetch the latest gamekey image from Docker hub using this command.
|
14
|
+
|
15
|
+
docker pull transit/gamekey
|
16
|
+
|
17
|
+
|
18
|
+
You can start the gamekey service like that
|
19
|
+
|
20
|
+
docker run -v $(pwd):/data -p 8080:8080 transit/gamekey
|
21
|
+
|
22
|
+
This will fire up a container with a running gamekey service on port 8080 on your host.
|
23
|
+
Gamekey states will be stored in a gamekey.json file under your current working directory.
|
24
|
+
(Only if you are using the volume option -v). You can have a look into your gamekey state via
|
25
|
+
|
26
|
+
cat gamekey.json
|
27
|
+
|
28
|
+
The docker installation provides only the server component in a handable manner.
|
29
|
+
The intended usage of this provisioning method is to run this service as a central server component.
|
30
|
+
|
31
|
+
## Installation via RubyGems (2nd Option)
|
32
|
+
|
33
|
+
To interact with this gamekey service you need a client. Gamekey is providing a command line client via RubyGems.org
|
34
|
+
for your convenience.
|
35
|
+
|
36
|
+
You will find here [Ruby](https://rvm.io/) installation instructions using rvm (Ruby Version Manager).
|
37
|
+
After you have installed rvm and Ruby 2.2 or higher successfully, you can install gamekey.
|
38
|
+
|
39
|
+
$ gem install gamekey
|
40
|
+
|
41
|
+
You can get basic usage instructions via:
|
42
|
+
|
43
|
+
$ gamekey help
|
44
|
+
|
45
|
+
If this is working, you have installed all gamekey components successfully.
|
46
|
+
|
47
|
+
## Usage
|
48
|
+
|
49
|
+
The gamekey package provides several basic commands to start and interact with the gamekey service.
|
50
|
+
|
51
|
+
|
52
|
+
### Start a gamekey service
|
53
|
+
|
54
|
+
$ gamekey start
|
55
|
+
|
56
|
+
starts the gamekey service at port 8080.
|
57
|
+
|
58
|
+
$ gamekey help start
|
59
|
+
|
60
|
+
provides additional usage instructions.
|
61
|
+
|
62
|
+
Another option is to start the gamekey service like shown in the Docker installation section.
|
63
|
+
|
64
|
+
### Register a game with the gamekey service
|
65
|
+
|
66
|
+
You have to register a game with the gamekey service to store gamestates.
|
67
|
+
To register a game you can use the register command like that.
|
68
|
+
|
69
|
+
$ gamekey register --host http://192.168.99.100:8080 --name SnakeGame > snakegame.json
|
70
|
+
|
71
|
+
This will connect the gamekey service to register a game with name 'SnakeGame'.
|
72
|
+
The anser is stored as a JSON file. It should look like that:
|
73
|
+
|
74
|
+
{
|
75
|
+
"type": "game",
|
76
|
+
"name": "SnakeGame",
|
77
|
+
"id": "29bb0d8d-d3ad-4c43-8916-1e9b5d21f2b0",
|
78
|
+
"url": "",
|
79
|
+
"signature": "IZmfTtGDQrsVkZNjzL115toJIoEtpGyaCcrKdV852RQ=",
|
80
|
+
"created": "2016-01-12T10:00:56.633213Z",
|
81
|
+
"secret": "965c444369346f26"
|
82
|
+
}
|
83
|
+
|
84
|
+
The command generated a random secret and unique id for the game.
|
85
|
+
|
86
|
+
__Be aware: The secret is only returned once! The secret is generated in the command line client
|
87
|
+
and not by the service itself. The gamekey service only stores
|
88
|
+
the signature, which can be only calculated by knowing id and secret. So if you are loosing your secret
|
89
|
+
your game has no access to the gamekey service any longer!__
|
90
|
+
|
91
|
+
Each game needs its _id_ and _secret_ for authentication and to do gamestate storing operations.
|
92
|
+
|
93
|
+
$ gamekey help register
|
94
|
+
|
95
|
+
provides additional usage instructions.
|
96
|
+
|
97
|
+
### Tests a gamekey service implementation
|
98
|
+
|
99
|
+
Your job is to analyze the gamekey service and reimplement it as a Dart service. Your game should work with
|
100
|
+
this reference implementation of the Gamekey Service but also with your Dart implementation.
|
101
|
+
|
102
|
+
You will find
|
103
|
+
|
104
|
+
- REST API reference implementation in method [GamekeyService::api](lib/gamekey.rb)
|
105
|
+
- REST API reference testcases in class [GamekeyReferenceTests](lib/reference.rb)
|
106
|
+
|
107
|
+
The provided gamekey service is implemented in Ruby and is tested against a number of test cases.
|
108
|
+
You can fire the same test cases against your Dart implementation using this command here:
|
109
|
+
|
110
|
+
$ gamekey test --host http://192.168.99.100:8080
|
111
|
+
|
112
|
+
Of course IP and port number should point at your Dart implementation and not at the Ruby reference implementation.
|
113
|
+
|
114
|
+
### Further commands
|
115
|
+
|
116
|
+
There are further commands to
|
117
|
+
|
118
|
+
- list all games
|
119
|
+
- update game data
|
120
|
+
- deregister games.
|
121
|
+
|
122
|
+
You get usage instructions via:
|
123
|
+
|
124
|
+
$ gamekey help list
|
125
|
+
$ gamekey help update
|
126
|
+
$ gamekey help deregister
|
127
|
+
|
128
|
+
## Get the sources
|
129
|
+
|
130
|
+
Gamekey is provided via Bitbucket as a public git repository.
|
131
|
+
So you can get all the sources via the following git command.
|
132
|
+
|
133
|
+
$ git clone https://nanekratzke@bitbucket.org/nanekratzke/gamekey.git
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/gamekey
ADDED
@@ -0,0 +1,232 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'commander/import'
|
4
|
+
require 'securerandom'
|
5
|
+
require 'json'
|
6
|
+
require 'terminal-table'
|
7
|
+
|
8
|
+
require 'gamekey'
|
9
|
+
require 'defaults'
|
10
|
+
require 'reference'
|
11
|
+
|
12
|
+
program :version, '0.0.1'
|
13
|
+
program :description, 'Command to launch, manage and test the gamekey service.'
|
14
|
+
default_command :help
|
15
|
+
|
16
|
+
#
|
17
|
+
# Gamekey command to start the gamekey service.
|
18
|
+
#
|
19
|
+
command :start do |c|
|
20
|
+
c.syntax = 'gamekey start [options]'
|
21
|
+
c.description = 'Starts gamekey service.'
|
22
|
+
c.option '--port NUMBER', Integer, "port number (optional, defaults to #{Defaults::PORT})"
|
23
|
+
c.option '--storage PATH', String, "key value storage file (optional, defaults to #{Defaults::STORAGE})"
|
24
|
+
c.action do |_, options|
|
25
|
+
|
26
|
+
options.default :port => Defaults::PORT
|
27
|
+
options.default :storage => Defaults::STORAGE
|
28
|
+
|
29
|
+
service = GamekeyService.new(storage: options.storage, port: options.port)
|
30
|
+
service.api.run!
|
31
|
+
# Add here some SSL certificate handling to support HTTPS
|
32
|
+
# - https://gist.github.com/TakahikoKawasaki/40ef0ab011b0a467bedf#file-sinatra-ssl-rb
|
33
|
+
# - http://stackoverflow.com/questions/11405161/can-i-enable-ssl-in-sinatra-with-thin
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# Gamekey command to run reference tests cases against a gamekey service.
|
39
|
+
#
|
40
|
+
command :test do |c|
|
41
|
+
c.syntax = 'gamekey test [options]'
|
42
|
+
c.description = 'Tests a gamekey service.'
|
43
|
+
c.option '--host HOST', String, "host of gamekey service to test (defaults to #{Defaults::TESTHOST})"
|
44
|
+
c.action do |_, options|
|
45
|
+
|
46
|
+
options.default :host => Defaults::TESTHOST
|
47
|
+
|
48
|
+
check = GamekeyReferenceTests.new(host: options.host)
|
49
|
+
check.userResourceHandling
|
50
|
+
check.gameResourceHandling
|
51
|
+
check.gamestateResourceHandling
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# Gamekey command to register a new game with gamekey service.
|
58
|
+
#
|
59
|
+
command :register do |c|
|
60
|
+
c.syntax = 'gamekey register [options]'
|
61
|
+
c.description = 'Registers a new game with the gamekey service.'
|
62
|
+
c.option '--host HOST', String, "host of gamekey service to register with (optional, defaults to #{Defaults::TESTHOST})"
|
63
|
+
c.option '--name STRING', String, "name of the new game (required, must be unique)"
|
64
|
+
c.option '--secret STRING', String, "secret of the game (optional, defaults to an autogenerated secret)"
|
65
|
+
c.option '--url HOST', String, "URI of the new game (optional, defaults to '')"
|
66
|
+
|
67
|
+
c.action do |_, options|
|
68
|
+
|
69
|
+
options.default :host => Defaults::TESTHOST
|
70
|
+
options.default :url => ""
|
71
|
+
options.default :secret => SecureRandom.hex(8)
|
72
|
+
|
73
|
+
if !options.name
|
74
|
+
puts "You have to provide a name with --name option."
|
75
|
+
exit(1)
|
76
|
+
end
|
77
|
+
|
78
|
+
uri = URI(options.host)
|
79
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
80
|
+
|
81
|
+
request = Net::HTTP::Post.new("/game")
|
82
|
+
request.set_form_data({
|
83
|
+
'name' => options.name,
|
84
|
+
'secret' => options.secret,
|
85
|
+
'url' => options.url
|
86
|
+
})
|
87
|
+
|
88
|
+
res = http.request(request)
|
89
|
+
|
90
|
+
unless res.code == "200"
|
91
|
+
puts "Uuups, there went something wrong."
|
92
|
+
puts "#{res.body}"
|
93
|
+
exit(1)
|
94
|
+
end
|
95
|
+
|
96
|
+
game = JSON.parse(res.body)
|
97
|
+
game['secret'] = options.secret
|
98
|
+
|
99
|
+
puts(JSON.pretty_generate(game))
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
# Gamekey command to list all games
|
105
|
+
#
|
106
|
+
command :list do |c|
|
107
|
+
c.syntax = 'gamekey list [options]'
|
108
|
+
c.description = 'Lists all registered games from the gamekey service.'
|
109
|
+
c.option '--host HOST', String, "host of gamekey service (optional, defaults to #{Defaults::TESTHOST})"
|
110
|
+
c.option '--json', "Return JSON like the REST API (optional, not set by default)"
|
111
|
+
|
112
|
+
c.action do |_, options|
|
113
|
+
|
114
|
+
options.default :host => Defaults::TESTHOST
|
115
|
+
options.default :json => false
|
116
|
+
|
117
|
+
uri = URI(options.host)
|
118
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
119
|
+
|
120
|
+
request = Net::HTTP::Get.new("/games")
|
121
|
+
res = http.request(request)
|
122
|
+
|
123
|
+
unless res.code == "200"
|
124
|
+
puts "Uuups, there went something wrong."
|
125
|
+
puts "#{res.body}"
|
126
|
+
exit(1)
|
127
|
+
end
|
128
|
+
|
129
|
+
games = JSON.parse(res.body)
|
130
|
+
|
131
|
+
puts JSON.pretty_generate(games) if options.json
|
132
|
+
unless options.json
|
133
|
+
rows = games.map { |game| [game['name'], game['id'], game['url']] }
|
134
|
+
table = Terminal::Table.new :headings => ['Game', 'ID', 'URL'], :rows => rows
|
135
|
+
puts table
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
#
|
141
|
+
# Gamekey command to update game data
|
142
|
+
#
|
143
|
+
command :update do |c|
|
144
|
+
c.syntax = 'gamekey update [options]'
|
145
|
+
c.description = 'Updates game data of registered game.'
|
146
|
+
c.option '--host HOST', String, "host of gamekey service (optional, defaults to #{Defaults::TESTHOST})"
|
147
|
+
c.option '--id STRING', String, "id of the game (required)"
|
148
|
+
c.option '--secret STRING', String, "secret of the game (required)"
|
149
|
+
c.option '--name STRING', String, "Update for the name of the game (optional, new name must be unique)"
|
150
|
+
c.option '--url STRING', String, "Update for the url of the game (optional, must be a valid url)"
|
151
|
+
c.option '--newsecret STRING', String, "Update for the secret of the game (optional)"
|
152
|
+
|
153
|
+
c.action do |_, options|
|
154
|
+
|
155
|
+
options.default :host => Defaults::TESTHOST
|
156
|
+
|
157
|
+
if !options.id
|
158
|
+
puts "You have to provide the id of the game with --id option."
|
159
|
+
exit(1)
|
160
|
+
end
|
161
|
+
|
162
|
+
if !options.secret
|
163
|
+
puts "You have to provide the secret with --secret option."
|
164
|
+
exit(1)
|
165
|
+
end
|
166
|
+
|
167
|
+
uri = URI(options.host)
|
168
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
169
|
+
|
170
|
+
request = Net::HTTP::Put.new("/game/#{options.id}")
|
171
|
+
params = {}
|
172
|
+
params['secret'] = options.secret
|
173
|
+
params['name'] = options.name if options.name
|
174
|
+
params['url'] = options.url if options.url
|
175
|
+
params['newsecret'] = options.newsecret if options.newsecret
|
176
|
+
request.set_form_data(params)
|
177
|
+
|
178
|
+
res = http.request(request)
|
179
|
+
|
180
|
+
unless res.code == "200"
|
181
|
+
puts "Uuups, there went something wrong."
|
182
|
+
puts "#{res.body}"
|
183
|
+
exit(1)
|
184
|
+
end
|
185
|
+
|
186
|
+
games = JSON.parse(res.body)
|
187
|
+
|
188
|
+
puts JSON.pretty_generate(games)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
|
193
|
+
#
|
194
|
+
# Gamekey command to deregister a new game with gamekey service.
|
195
|
+
#
|
196
|
+
command :deregister do |c|
|
197
|
+
c.syntax = 'gamekey deregister [options]'
|
198
|
+
c.description = 'Deregisters a game from the gamekey service.'
|
199
|
+
c.option '--host HOST', String, "host of gamekey service (optional, defaults to #{Defaults::TESTHOST})"
|
200
|
+
c.option '--id STRING', String, "id of the game (required)"
|
201
|
+
c.option '--secret STRING', String, "secret of the game (required)"
|
202
|
+
|
203
|
+
c.action do |_, options|
|
204
|
+
|
205
|
+
options.default :host => Defaults::TESTHOST
|
206
|
+
|
207
|
+
if !options.id
|
208
|
+
puts "You have to provide the id of the game with --id option."
|
209
|
+
exit(1)
|
210
|
+
end
|
211
|
+
|
212
|
+
if !options.secret
|
213
|
+
puts "You have to provide the secret with --secret option."
|
214
|
+
exit(1)
|
215
|
+
end
|
216
|
+
|
217
|
+
uri = URI(options.host)
|
218
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
219
|
+
|
220
|
+
request = Net::HTTP::Delete.new("/game/#{options.id}")
|
221
|
+
request.set_form_data({ 'secret' => options.secret })
|
222
|
+
res = http.request(request)
|
223
|
+
|
224
|
+
unless res.code == "200"
|
225
|
+
puts "Uuups, there went something wrong."
|
226
|
+
puts "#{res.body}"
|
227
|
+
exit(1)
|
228
|
+
end
|
229
|
+
|
230
|
+
puts ("Game deleted: #{res.body}")
|
231
|
+
end
|
232
|
+
end
|
data/gamekey.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'gamekey/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "gamekey"
|
8
|
+
spec.version = Gamekey::VERSION
|
9
|
+
spec.authors = ["Nane Kratzke"]
|
10
|
+
spec.email = ["nane.kratzke@fh-luebeck.de"]
|
11
|
+
spec.description = %q{Gamekey service.}
|
12
|
+
spec.summary = %q{Gamekey service.}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.required_ruby_version = '>= 2.2.0'
|
22
|
+
|
23
|
+
spec.add_runtime_dependency "sinatra"
|
24
|
+
spec.add_runtime_dependency "sinatra-cross_origin"
|
25
|
+
spec.add_runtime_dependency "commander"
|
26
|
+
spec.add_runtime_dependency "colorize"
|
27
|
+
spec.add_runtime_dependency "terminal-table"
|
28
|
+
|
29
|
+
|
30
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
31
|
+
spec.add_development_dependency "rake"
|
32
|
+
end
|
data/lib/auth.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'defaults'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
module Auth
|
5
|
+
|
6
|
+
def self.signature(id, pwd)
|
7
|
+
Base64.strict_encode64(Defaults::CRYPTOHASH.digest("#{id},#{pwd}"))
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.authentic?(entity, pwd)
|
11
|
+
entity['signature'] == signature(entity['id'], pwd)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|