satz 0.0.1 → 0.0.2

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.
Files changed (7) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +4 -0
  3. data/README.md +48 -2
  4. data/lib/satz.rb +63 -4
  5. data/satz.gemspec +1 -1
  6. data/test/all.rb +61 -4
  7. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ef06f388d1b3113f7d709320b4ea4606e5fc9c8c
4
- data.tar.gz: af63d424f6e74e95418804514075f72886777af5
3
+ metadata.gz: 5ef14c47b68ac506c9096dfa78e62d7e174d3dd4
4
+ data.tar.gz: eb243d56d8184dda598263589bcbfe7e5580bb2f
5
5
  SHA512:
6
- metadata.gz: 8ef33ff001e893d12588c6fbf6f5825434c7cf8599f14db51ddf12b807e95ccb0e6731f9ff4241a80e6b587e6bec31ec827c3f4ddd919fb853eef807317deccc
7
- data.tar.gz: 4a1df71be2425e688e51ed96dafb3d0a8d1d3be929f8f5c2917e8a7788382942d4c1018b5b1e7846f3d933179c98f6eec6df42a58a24a744598b555c8675dd90
6
+ metadata.gz: a1025b3c94d78c146c7cee02a24be964ae9b4fef849855d954e3dff793fc901dcd405b175155ea8fb159227a0b9d32ab61854f969242a0e41880aa7430b15fd6
7
+ data.tar.gz: cb37e3aabca0617d18c8730f815fc3997843a1528b3eca6834c985acd41fec8009486126d4072c229948308efd24a090cb1c2721477d036a20628486bde0b934
data/CHANGELOG CHANGED
@@ -1 +1,5 @@
1
+ 0.0.2
1
2
 
3
+ * Add customizable serializer
4
+
5
+ * Add authentication via Basic Auth
data/README.md CHANGED
@@ -19,7 +19,7 @@ Usage
19
19
  An example of a Satz application would look like this:
20
20
 
21
21
  ```ruby
22
- App = Satz.new do
22
+ App = Satz.define do
23
23
  on "players" do
24
24
  on :player_id do
25
25
  get do
@@ -55,15 +55,61 @@ In user defined objects, you can define the method `to_json` according
55
55
  to your needs. Most ORMs already provide meaningful definitions for
56
56
  that method.
57
57
 
58
+ Authentication
59
+ --------------
60
+
61
+ The `auth` method checks if Basic Auth headers were provided and
62
+ returns `nil` otherwise. If it's able to access the supplied
63
+ credentials, it yield the username and password and returns the
64
+ result (if it's not false) or nil.
65
+
66
+ Here's an example of how to use it:
67
+
68
+ ```ruby
69
+ @user = auth do |user, pass|
70
+
71
+ # Here you can use any method of your
72
+ # choice. The example is from Shield.
73
+ User.authenticate(user, pass)
74
+ end
75
+
76
+ on @user.nil? do
77
+ res.status = 401
78
+ reply(error: "Unauthorized")
79
+ end
80
+ ```
81
+
82
+ Anything defined after that `on` block will be executed only if the
83
+ authentication succeded.
84
+
85
+ Serialization
86
+ -------------
87
+
88
+ The default serializer is `JSON`, but it can be customized by
89
+ supplying a serializer:
90
+
91
+ ```ruby
92
+ Satz.serializer = MySerializer
93
+ ```
94
+
95
+ A serializer must respond to `load(arg)` and `dump(arg)`, and that's
96
+ the only restriction. Note that the supplied serializer will be used
97
+ by all `Satz` applications.
98
+
58
99
  API
59
100
  ---
60
101
 
61
102
  Apart from [Syro][syro]'s API, the following methods are available:
62
103
 
63
- `read`: Reads the body of the requst and parses it as JSON.
104
+ `auth`: Process Basic Auth headers and yield username and password.
105
+
106
+ `read`: Reads the body of the request and parses it as JSON.
64
107
 
65
108
  `reply`: Writes to the response its argument encoded as JSON.
66
109
 
110
+ Installation
111
+ ------------
112
+
67
113
  ```
68
114
  $ gem install satz
69
115
  ```
data/lib/satz.rb CHANGED
@@ -22,24 +22,83 @@
22
22
 
23
23
  require "syro"
24
24
  require "json"
25
+ require "base64"
25
26
 
26
27
  class Satz
28
+
29
+ # The JSON module from stdlib provides a safe way of loading data
30
+ # with the `parse` method, but the most widespread API for encoding
31
+ # and decoding data is with the `load` and `dump` methods, which in
32
+ # the case of JSON are unsafe. This module wraps the JSON constant
33
+ # from stdlib in order to expose a safe version of `load`. As the
34
+ # serializer is configurable, the user is expected to provide
35
+ # objects that respond safely to those methods.
36
+ module Serializer
37
+ def self.load(value)
38
+ JSON.load(value, nil, create_additions: false)
39
+ end
40
+
41
+ def self.dump(value)
42
+ JSON.dump(value)
43
+ end
44
+ end
45
+
46
+ @@serializer = Serializer
47
+
48
+ def self.serializer
49
+ @@serializer
50
+ end
51
+
52
+ # Modify the serializer to be used for all Satz applications.
53
+ # The serializer object must reply to `load(arg)` and `dump(arg)`.
54
+ def self.serializer=(value)
55
+ @@serializer = value
56
+ end
57
+
27
58
  class Deck < Syro::Deck
59
+ HTTP_AUTHORIZATION = "HTTP_AUTHORIZATION".freeze
60
+
61
+ # Checks the Basic Auth headers and yields
62
+ # user and pass if credentials are provided.
63
+ # Returns nil if there are no credentials or
64
+ # if the block returns false or nil.
65
+ #
66
+ # Usage:
67
+ #
68
+ # @user = auth do |user, pass|
69
+ # User.authenticate(user, pass)
70
+ # end
71
+ #
72
+ # on @user.nil? do
73
+ # res.status = 401
74
+ # reply(error: "Unauthorized")
75
+ # end
76
+ #
77
+ def auth
78
+ http_auth = env.fetch(HTTP_AUTHORIZATION) do
79
+ return nil
80
+ end
81
+
82
+ cred = http_auth.split(" ")[1]
83
+ user, pass = Base64.decode64(cred).split(":")
84
+
85
+ yield(user, pass) || nil
86
+ end
28
87
 
29
- # Respond by default with JSON.
88
+ # Respond by default with JSON. The default charset
89
+ # for "application/json" is UTF-8.
30
90
  def default_headers
31
91
  { "Content-Type" => "application/json" }
32
92
  end
33
93
 
34
94
  # Read JSON data from the POST request.
35
95
  def read
36
- body = req.body.read
37
- body && JSON.parse(body)
96
+ Satz.serializer.load(req.body.read)
38
97
  end
39
98
 
40
99
  # Write JSON data to the response.
41
100
  def reply(data)
42
- res.write(JSON.dump(data))
101
+ res.write(Satz.serializer.dump(data))
43
102
  end
44
103
  end
45
104
 
data/satz.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "satz"
3
- s.version = "0.0.1"
3
+ s.version = "0.0.2"
4
4
  s.summary = "Framework for JSON microservices"
5
5
  s.description = "Framework for JSON microservices"
6
6
  s.authors = ["Michel Martens"]
data/test/all.rb CHANGED
@@ -1,22 +1,37 @@
1
- App = Satz.define do
1
+ A1 = Satz.define do
2
2
  get do
3
- reply(true)
3
+ reply(read)
4
4
  end
5
5
 
6
6
  post do
7
7
  reply(read)
8
8
  end
9
+
10
+ on "protected" do
11
+ @user = auth do |user, pass|
12
+ user == "foo" && pass == "bar"
13
+ end
14
+
15
+ on @user.nil? do
16
+ res.status = 401
17
+ reply(error: "Unauthorized")
18
+ end
19
+
20
+ get do
21
+ reply(true)
22
+ end
23
+ end
9
24
  end
10
25
 
11
26
  setup do
12
- Driver.new(App)
27
+ Driver.new(A1)
13
28
  end
14
29
 
15
30
  test "get" do |app|
16
31
  app.get("/")
17
32
 
18
33
  assert_equal 200, app.last_response.status
19
- assert_equal %Q(true), app.last_response.body
34
+ assert_equal %Q(null), app.last_response.body
20
35
  end
21
36
 
22
37
  test "post" do |app|
@@ -27,3 +42,45 @@ test "post" do |app|
27
42
  assert_equal data, app.last_response.body
28
43
  assert_equal 200, app.last_response.status
29
44
  end
45
+
46
+ test "auth" do |app|
47
+ app.get("/protected")
48
+
49
+ assert_equal %Q({"error":"Unauthorized"}), app.last_response.body
50
+ assert_equal 401, app.last_response.status
51
+
52
+ app.authorize("foo", "bar")
53
+
54
+ app.get("/protected")
55
+
56
+ assert_equal %Q(true), app.last_response.body
57
+ end
58
+
59
+ module Reverser
60
+ def self.load(data)
61
+ data
62
+ end
63
+
64
+ def self.dump(data)
65
+ data.reverse
66
+ end
67
+ end
68
+
69
+ Satz.serializer = Reverser
70
+
71
+ A2 = Satz.define do
72
+ get do
73
+ reply("hello")
74
+ end
75
+ end
76
+
77
+ setup do
78
+ Driver.new(A2)
79
+ end
80
+
81
+ test "get" do |app|
82
+ app.get("/")
83
+
84
+ assert_equal 200, app.last_response.status
85
+ assert_equal %Q(olleh), app.last_response.body
86
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: satz
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michel Martens
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-11 00:00:00.000000000 Z
11
+ date: 2016-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: syro