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.
@@ -0,0 +1,13 @@
1
+ FROM ruby:2.2
2
+
3
+ COPY . /usr/src/app
4
+ WORKDIR /usr/src/app
5
+ RUN bundle install
6
+ RUN rake install
7
+
8
+ VOLUME ["/data/"]
9
+
10
+ EXPOSE 8080
11
+
12
+ ENTRYPOINT ["gamekey", "start"]
13
+ CMD ["--storage", "/data/gamekey.json"]
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gamekey.gemspec
4
+ gemspec
@@ -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.
@@ -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
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -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
@@ -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
@@ -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