tynn 1.0.0.rc1 → 1.0.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/tynn.rb +49 -15
- data/lib/tynn/all_methods.rb +12 -10
- data/lib/tynn/environment.rb +39 -37
- data/lib/tynn/erubis.rb +10 -8
- data/lib/tynn/json.rb +36 -5
- data/lib/tynn/matchers.rb +49 -47
- data/lib/tynn/not_found.rb +12 -10
- data/lib/tynn/protection.rb +35 -6
- data/lib/tynn/render.rb +34 -42
- data/lib/tynn/request.rb +2 -0
- data/lib/tynn/response.rb +36 -2
- data/lib/tynn/secure_headers.rb +42 -40
- data/lib/tynn/session.rb +80 -78
- data/lib/tynn/ssl.rb +52 -50
- data/lib/tynn/static.rb +34 -32
- data/lib/tynn/test.rb +42 -40
- data/lib/tynn/version.rb +2 -2
- data/test/core_test.rb +0 -8
- data/test/middleware_test.rb +4 -4
- data/test/render_test.rb +1 -1
- metadata +5 -11
- data/lib/tynn/hmote.rb +0 -40
- data/lib/tynn/json_parser.rb +0 -36
- data/test/hmote_test.rb +0 -78
- data/test/json_parser_test.rb +0 -22
data/lib/tynn/ssl.rb
CHANGED
@@ -1,71 +1,73 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
class Middleware # :nodoc:
|
7
|
-
def initialize(app, hsts: {})
|
8
|
-
@app = app
|
9
|
-
@hsts_header = build_hsts_header(hsts)
|
1
|
+
class Tynn
|
2
|
+
module SSL
|
3
|
+
def self.setup(app, hsts: {}) # :nodoc:
|
4
|
+
app.use(Tynn::SSL::Middleware, hsts: hsts)
|
10
5
|
end
|
11
6
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
return [301, redirect_headers(request), []]
|
7
|
+
class Middleware # :nodoc:
|
8
|
+
def initialize(app, hsts: {})
|
9
|
+
@app = app
|
10
|
+
@hsts_header = build_hsts_header(hsts)
|
17
11
|
end
|
18
12
|
|
19
|
-
|
13
|
+
def call(env)
|
14
|
+
request = Rack::Request.new(env)
|
20
15
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
return result
|
25
|
-
end
|
16
|
+
unless request.ssl?
|
17
|
+
return [301, redirect_headers(request), []]
|
18
|
+
end
|
26
19
|
|
27
|
-
|
20
|
+
result = @app.call(env)
|
28
21
|
|
29
|
-
|
30
|
-
|
22
|
+
set_hsts_header(result[1])
|
23
|
+
set_cookies_as_secure(result[1])
|
31
24
|
|
32
|
-
|
33
|
-
|
34
|
-
header << "; includeSubdomains" if options.fetch(:subdomains, true)
|
35
|
-
header << "; preload" if options[:preload]
|
25
|
+
return result
|
26
|
+
end
|
36
27
|
|
37
|
-
|
38
|
-
end
|
28
|
+
private
|
39
29
|
|
40
|
-
|
41
|
-
|
42
|
-
"Content-Type" => "text/html",
|
43
|
-
"Location" => https_location(request)
|
44
|
-
}
|
45
|
-
end
|
30
|
+
HSTS_HEADER = "Strict-Transport-Security".freeze
|
31
|
+
HSTS_EXPIRE = 15_552_000 # 180 days
|
46
32
|
|
47
|
-
|
33
|
+
def build_hsts_header(options)
|
34
|
+
header = sprintf("max-age=%i", options.fetch(:expires, HSTS_EXPIRE))
|
35
|
+
header << "; includeSubdomains" if options.fetch(:subdomains, true)
|
36
|
+
header << "; preload" if options[:preload]
|
48
37
|
|
49
|
-
|
50
|
-
|
51
|
-
end
|
38
|
+
return header
|
39
|
+
end
|
52
40
|
|
53
|
-
|
54
|
-
|
55
|
-
|
41
|
+
def redirect_headers(request)
|
42
|
+
return {
|
43
|
+
"Content-Type" => "text/html",
|
44
|
+
"Location" => https_location(request)
|
45
|
+
}
|
46
|
+
end
|
56
47
|
|
57
|
-
|
58
|
-
COOKIE_SEPARATOR = "\n".freeze
|
59
|
-
COOKIE_REGEXP = /;\s*secure\s*(;|$)/i
|
48
|
+
HTTPS_LOCATION = "https://%s%s".freeze
|
60
49
|
|
61
|
-
|
62
|
-
|
50
|
+
def https_location(request)
|
51
|
+
return sprintf(HTTPS_LOCATION, request.host, request.fullpath)
|
52
|
+
end
|
63
53
|
|
64
|
-
|
65
|
-
|
54
|
+
def set_hsts_header(headers)
|
55
|
+
headers[HSTS_HEADER] = @hsts_header
|
66
56
|
end
|
67
57
|
|
68
|
-
|
58
|
+
COOKIE_HEADER = "Set-Cookie".freeze
|
59
|
+
COOKIE_SEPARATOR = "\n".freeze
|
60
|
+
COOKIE_REGEXP = /;\s*secure\s*(;|$)/i
|
61
|
+
|
62
|
+
def set_cookies_as_secure(headers)
|
63
|
+
return unless cookies = headers[COOKIE_HEADER]
|
64
|
+
|
65
|
+
cookies = cookies.split(COOKIE_SEPARATOR).map do |cookie|
|
66
|
+
(cookie !~ COOKIE_REGEXP) ? "#{ cookie }; secure" : cookie
|
67
|
+
end
|
68
|
+
|
69
|
+
headers[COOKIE_HEADER] = cookies.join(COOKIE_SEPARATOR)
|
70
|
+
end
|
69
71
|
end
|
70
72
|
end
|
71
73
|
end
|
data/lib/tynn/static.rb
CHANGED
@@ -1,36 +1,38 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# require "tynn
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
|
28
|
-
|
29
|
-
options =
|
1
|
+
class Tynn
|
2
|
+
# Adds support for static files (javascript files, images, stylesheets, etc).
|
3
|
+
#
|
4
|
+
# ```
|
5
|
+
# require "tynn"
|
6
|
+
# require "tynn/static"
|
7
|
+
#
|
8
|
+
# Tynn.helpers(Tynn::Static, ["/js", "/css"])
|
9
|
+
# ```
|
10
|
+
#
|
11
|
+
# By default, serve all requests beginning with the given paths from the folder
|
12
|
+
# `public` in the current directory (e.g. `public/js/*`, `public/css/*`). You
|
13
|
+
# can change the default by passing the `:root` option.
|
14
|
+
#
|
15
|
+
# ```
|
16
|
+
# Tynn.helpers(Tynn::Static, ["/js", "/css"], root: "assets")
|
17
|
+
# ```
|
18
|
+
#
|
19
|
+
# Under the hood, it uses the [Rack::Static][rack-static] middleware.
|
20
|
+
# Thus, supports all the options available for this middleware.
|
21
|
+
#
|
22
|
+
# ```
|
23
|
+
# Tynn.helpers(Tynn::Static, ["/js", "/css"], index: "index.html")
|
24
|
+
# ```
|
25
|
+
#
|
26
|
+
# [rack-static]: http://www.rubydoc.info/gems/rack/Rack/Static
|
27
|
+
#
|
28
|
+
module Static
|
29
|
+
def self.setup(app, urls, options = {}) # :nodoc:
|
30
|
+
options = options.dup
|
30
31
|
|
31
|
-
|
32
|
-
|
32
|
+
options[:urls] ||= urls
|
33
|
+
options[:root] ||= File.expand_path("public", Dir.pwd)
|
33
34
|
|
34
|
-
|
35
|
+
app.use(Rack::Static, options)
|
36
|
+
end
|
35
37
|
end
|
36
38
|
end
|
data/lib/tynn/test.rb
CHANGED
@@ -1,51 +1,53 @@
|
|
1
1
|
require "rack/test"
|
2
2
|
|
3
|
-
|
4
|
-
# to
|
5
|
-
#
|
6
|
-
# ```
|
7
|
-
# require "tynn"
|
8
|
-
# require "tynn/test"
|
9
|
-
#
|
10
|
-
# Tynn.define do
|
11
|
-
# root do
|
12
|
-
# res.write("hei")
|
13
|
-
# end
|
14
|
-
# end
|
15
|
-
#
|
16
|
-
# app = Tynn::Test.new
|
17
|
-
# app.get("/")
|
18
|
-
#
|
19
|
-
# 200 == app.res.status # => true
|
20
|
-
# "hei" == app.res.body # => true
|
21
|
-
# ```
|
22
|
-
#
|
23
|
-
# **NOTE:** Tynn doesn't ship with [rack-test][rack-test]. In order to
|
24
|
-
# use this plugin, you need to install it first.
|
25
|
-
#
|
26
|
-
# [rack-test]: http://rubygems.org/gems/rack-test
|
27
|
-
#
|
28
|
-
class Tynn::Test
|
29
|
-
include Rack::Test::Methods
|
30
|
-
|
31
|
-
# Instantiates a new Tynn::Test object with the given `application` to test.
|
3
|
+
class Tynn
|
4
|
+
# A simple helper class that uses [rack-test][rack-test] to simulate requests
|
5
|
+
# to your application.
|
32
6
|
#
|
33
7
|
# ```
|
34
|
-
#
|
8
|
+
# require "tynn"
|
9
|
+
# require "tynn/test"
|
10
|
+
#
|
11
|
+
# Tynn.define do
|
12
|
+
# root do
|
13
|
+
# res.write("hei")
|
14
|
+
# end
|
35
15
|
# end
|
36
16
|
#
|
37
|
-
# app = Tynn::Test.new
|
38
|
-
# app.get("/
|
17
|
+
# app = Tynn::Test.new
|
18
|
+
# app.get("/")
|
19
|
+
#
|
20
|
+
# 200 == app.res.status # => true
|
21
|
+
# "hei" == app.res.body # => true
|
39
22
|
# ```
|
40
23
|
#
|
41
|
-
|
42
|
-
|
43
|
-
|
24
|
+
# **NOTE:** Tynn doesn't ship with [rack-test][rack-test]. In order to
|
25
|
+
# use this plugin, you need to install it first.
|
26
|
+
#
|
27
|
+
# [rack-test]: http://rubygems.org/gems/rack-test
|
28
|
+
#
|
29
|
+
class Test
|
30
|
+
include Rack::Test::Methods
|
44
31
|
|
45
|
-
|
46
|
-
|
47
|
-
|
32
|
+
# Instantiates a new Tynn::Test object with the given `application` to test.
|
33
|
+
#
|
34
|
+
# ```
|
35
|
+
# class API < Tynn
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# app = Tynn::Test.new(API)
|
39
|
+
# app.get("/json")
|
40
|
+
# ```
|
41
|
+
#
|
42
|
+
def initialize(application = Tynn)
|
43
|
+
@app = application
|
44
|
+
end
|
48
45
|
|
49
|
-
|
50
|
-
|
46
|
+
def app # :nodoc:
|
47
|
+
return @app
|
48
|
+
end
|
49
|
+
|
50
|
+
alias_method :res, :last_response
|
51
|
+
alias_method :req, :last_request
|
52
|
+
end
|
51
53
|
end
|
data/lib/tynn/version.rb
CHANGED
data/test/core_test.rb
CHANGED
data/test/middleware_test.rb
CHANGED
@@ -54,16 +54,16 @@ test "middleware with composition" do
|
|
54
54
|
end
|
55
55
|
|
56
56
|
test "middleware only in child application" do
|
57
|
+
class API < Tynn
|
58
|
+
use(Shrimp)
|
59
|
+
end
|
60
|
+
|
57
61
|
Tynn.define do
|
58
62
|
on "api" do
|
59
63
|
run(API)
|
60
64
|
end
|
61
65
|
end
|
62
66
|
|
63
|
-
class API < Tynn
|
64
|
-
use(Shrimp)
|
65
|
-
end
|
66
|
-
|
67
67
|
API.define do
|
68
68
|
get do
|
69
69
|
res.write("1")
|
data/test/render_test.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tynn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.rc2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Francesco Rodríguez
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-10-
|
11
|
+
date: 2015-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -122,7 +122,7 @@ dependencies:
|
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '2.0'
|
125
|
-
description:
|
125
|
+
description: Thin library to create web applications
|
126
126
|
email:
|
127
127
|
- frodsan@protonmail.ch
|
128
128
|
executables: []
|
@@ -135,9 +135,7 @@ files:
|
|
135
135
|
- lib/tynn/all_methods.rb
|
136
136
|
- lib/tynn/environment.rb
|
137
137
|
- lib/tynn/erubis.rb
|
138
|
-
- lib/tynn/hmote.rb
|
139
138
|
- lib/tynn/json.rb
|
140
|
-
- lib/tynn/json_parser.rb
|
141
139
|
- lib/tynn/matchers.rb
|
142
140
|
- lib/tynn/not_found.rb
|
143
141
|
- lib/tynn/protection.rb
|
@@ -155,8 +153,6 @@ files:
|
|
155
153
|
- test/environment_test.rb
|
156
154
|
- test/erubis_test.rb
|
157
155
|
- test/helper.rb
|
158
|
-
- test/hmote_test.rb
|
159
|
-
- test/json_parser_test.rb
|
160
156
|
- test/json_test.rb
|
161
157
|
- test/matchers_test.rb
|
162
158
|
- test/middleware_test.rb
|
@@ -167,7 +163,7 @@ files:
|
|
167
163
|
- test/session_test.rb
|
168
164
|
- test/ssl_test.rb
|
169
165
|
- test/static_test.rb
|
170
|
-
homepage: https://github.com/
|
166
|
+
homepage: https://github.com/frodsan/tynn
|
171
167
|
licenses:
|
172
168
|
- MIT
|
173
169
|
metadata: {}
|
@@ -190,15 +186,13 @@ rubyforge_project:
|
|
190
186
|
rubygems_version: 2.4.8
|
191
187
|
signing_key:
|
192
188
|
specification_version: 4
|
193
|
-
summary:
|
189
|
+
summary: Thin library to create web applications
|
194
190
|
test_files:
|
195
191
|
- test/all_methods_test.rb
|
196
192
|
- test/core_test.rb
|
197
193
|
- test/environment_test.rb
|
198
194
|
- test/erubis_test.rb
|
199
195
|
- test/helper.rb
|
200
|
-
- test/hmote_test.rb
|
201
|
-
- test/json_parser_test.rb
|
202
196
|
- test/json_test.rb
|
203
197
|
- test/matchers_test.rb
|
204
198
|
- test/middleware_test.rb
|
data/lib/tynn/hmote.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
require "hmote"
|
2
|
-
|
3
|
-
module Tynn::HMote
|
4
|
-
include ::HMote::Helpers
|
5
|
-
|
6
|
-
def self.setup(app, options = {}) # :nodoc:
|
7
|
-
options = options.dup
|
8
|
-
|
9
|
-
options[:layout] ||= "layout"
|
10
|
-
options[:views] ||= File.expand_path("views", Dir.pwd)
|
11
|
-
|
12
|
-
app.settings[:hmote] ||= options
|
13
|
-
end
|
14
|
-
|
15
|
-
module ClassMethods
|
16
|
-
def layout(layout)
|
17
|
-
settings[:hmote][:layout] = layout
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def render(template, locals = {}, layout = settings[:hmote][:layout])
|
22
|
-
res.headers[Rack::CONTENT_TYPE] ||= Syro::Response::DEFAULT
|
23
|
-
|
24
|
-
res.write(view(template, locals, layout))
|
25
|
-
end
|
26
|
-
|
27
|
-
def view(template, locals = {}, layout = settings[:hmote][:layout])
|
28
|
-
return partial(layout, locals.merge(content: partial(template, locals)))
|
29
|
-
end
|
30
|
-
|
31
|
-
def partial(template, locals = {})
|
32
|
-
return hmote(template_path(template), locals.merge(app: self), TOPLEVEL_BINDING)
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def template_path(template)
|
38
|
-
return File.join(settings[:hmote][:views], "#{ template }.mote")
|
39
|
-
end
|
40
|
-
end
|