tynn 0.0.4 → 1.0.0.rc1
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 +4 -4
- data/lib/tynn/all_methods.rb +17 -0
- data/lib/tynn/environment.rb +12 -8
- data/lib/tynn/matchers.rb +37 -19
- data/lib/tynn/request.rb +4 -0
- data/lib/tynn/response.rb +151 -0
- data/lib/tynn/secure_headers.rb +28 -4
- data/lib/tynn/session.rb +74 -3
- data/lib/tynn/ssl.rb +2 -2
- data/lib/tynn/static.rb +26 -0
- data/lib/tynn/test.rb +37 -2
- data/lib/tynn/version.rb +7 -2
- data/lib/tynn.rb +88 -8
- data/test/all_methods_test.rb +16 -0
- data/test/core_test.rb +0 -86
- data/test/matchers_test.rb +11 -8
- data/test/middleware_test.rb +79 -0
- data/test/protection_test.rb +37 -0
- data/test/session_test.rb +1 -6
- metadata +45 -52
- data/.gems +0 -10
- data/docs/bin/build +0 -38
- data/docs/guides/security.md +0 -1
- data/docs/index.md +0 -89
- data/docs/layout.html +0 -61
- data/docs/public/.gitignore +0 -1
- data/docs/public/css/styles.css +0 -111
- data/docs/public/guides/.gitignore +0 -2
- data/docs/syro/syro.rb +0 -112
- data/examples/composition.ru +0 -40
- data/examples/hello.ru +0 -9
- data/examples/protection.ru +0 -18
- data/examples/render.ru +0 -13
- data/examples/views/home.erb +0 -1
- data/examples/views/layout.erb +0 -5
- data/lib/tynn/csrf.rb +0 -48
- data/lib/tynn/options.rb +0 -9
- data/makefile +0 -15
- data/test/csrf_test.rb +0 -98
- data/test/options_test.rb +0 -16
- data/test/views/custom_layout.erb +0 -1
- data/test/views/custom_layout.mote +0 -1
- data/test/views/layout.erb +0 -1
- data/test/views/layout.mote +0 -1
- data/test/views/partial.erb +0 -1
- data/test/views/partial.mote +0 -1
- data/test/views/view.erb +0 -1
- data/test/views/view.mote +0 -1
- data/tynn.gemspec +0 -24
data/docs/public/css/styles.css
DELETED
@@ -1,111 +0,0 @@
|
|
1
|
-
html {
|
2
|
-
font-family: "Roboto";
|
3
|
-
}
|
4
|
-
|
5
|
-
body {
|
6
|
-
color: rgba(0, 0, 0, 0.87);
|
7
|
-
font-size: 16px;
|
8
|
-
font-weight: 400;
|
9
|
-
margin: 0;
|
10
|
-
padding: 0;
|
11
|
-
}
|
12
|
-
|
13
|
-
.container {
|
14
|
-
padding-top: 64px;
|
15
|
-
min-width: 960px;
|
16
|
-
}
|
17
|
-
|
18
|
-
header {
|
19
|
-
background: #2196F3;
|
20
|
-
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
|
21
|
-
height: 64px;
|
22
|
-
position: fixed;
|
23
|
-
top: 0;
|
24
|
-
width: 100%;
|
25
|
-
text-align: right;
|
26
|
-
}
|
27
|
-
|
28
|
-
h1 {
|
29
|
-
color: rgba(0, 0, 0, 0.54);
|
30
|
-
font-size: 34px;
|
31
|
-
font-weight: 400;
|
32
|
-
}
|
33
|
-
|
34
|
-
h2 {
|
35
|
-
font-size: 24px;
|
36
|
-
font-weight: 400;
|
37
|
-
}
|
38
|
-
|
39
|
-
h3 {
|
40
|
-
font-size: 16px;
|
41
|
-
font-weight: 500;
|
42
|
-
}
|
43
|
-
|
44
|
-
.wrap {
|
45
|
-
width: 960px;
|
46
|
-
margin-left: auto;
|
47
|
-
margin-right: auto;
|
48
|
-
padding-left: 20px;
|
49
|
-
padding-right: 20px;
|
50
|
-
}
|
51
|
-
|
52
|
-
header a {
|
53
|
-
color: white;
|
54
|
-
line-height: 64px;
|
55
|
-
text-decoration: none;
|
56
|
-
}
|
57
|
-
|
58
|
-
.nav-home {
|
59
|
-
float: left;
|
60
|
-
font-size: 24px;
|
61
|
-
letter-spacing: 2px;
|
62
|
-
}
|
63
|
-
|
64
|
-
.nav-github {
|
65
|
-
font-size: 32px;
|
66
|
-
}
|
67
|
-
|
68
|
-
.content {
|
69
|
-
padding-top: 20px;
|
70
|
-
}
|
71
|
-
|
72
|
-
.nav-docs {
|
73
|
-
float: left;
|
74
|
-
width: 21.875%;
|
75
|
-
}
|
76
|
-
|
77
|
-
.nav-docs-section {
|
78
|
-
border-top: 1px solid rgba(0, 0, 0, 0.12);
|
79
|
-
padding: 12px 0;
|
80
|
-
}
|
81
|
-
|
82
|
-
.nav-docs-section:first-child {
|
83
|
-
padding-top: 0;
|
84
|
-
border-top: 0;
|
85
|
-
}
|
86
|
-
|
87
|
-
.nav-docs ul {
|
88
|
-
list-style: none;
|
89
|
-
padding: 0;
|
90
|
-
}
|
91
|
-
|
92
|
-
.nav-docs ul a {
|
93
|
-
color: rgba(0, 0, 0, 0.87);
|
94
|
-
font-size: 14px;
|
95
|
-
line-height: 24px;
|
96
|
-
text-decoration: none;
|
97
|
-
}
|
98
|
-
|
99
|
-
.nav-docs ul a:hover {
|
100
|
-
color: #FF4081;
|
101
|
-
}
|
102
|
-
|
103
|
-
.nav-docs ul ul {
|
104
|
-
padding-left: 20px;
|
105
|
-
}
|
106
|
-
|
107
|
-
.inner-content {
|
108
|
-
float: right;
|
109
|
-
line-height: 24px;
|
110
|
-
width: 67.7083%;
|
111
|
-
}
|
data/docs/syro/syro.rb
DELETED
@@ -1,112 +0,0 @@
|
|
1
|
-
class Syro::Response
|
2
|
-
##
|
3
|
-
# :method: []
|
4
|
-
#
|
5
|
-
# Returns the response header corresponding to `key`.
|
6
|
-
#
|
7
|
-
# res["Content-Type"] # => "text/html"
|
8
|
-
# res["Content-Length"] # => "42"
|
9
|
-
|
10
|
-
##
|
11
|
-
# :method: []=
|
12
|
-
# :call-seq: []=(value)
|
13
|
-
#
|
14
|
-
# Sets the given `value` with the header corresponding to `key`.
|
15
|
-
#
|
16
|
-
# res["Content-Type"] = "application/json"
|
17
|
-
# res["Content-Type"] # => "application/json"
|
18
|
-
|
19
|
-
##
|
20
|
-
# :method: body
|
21
|
-
#
|
22
|
-
# Returns the body of the response.
|
23
|
-
#
|
24
|
-
# res.body
|
25
|
-
# # => []
|
26
|
-
#
|
27
|
-
# res.write("there is")
|
28
|
-
# res.write("no try")
|
29
|
-
#
|
30
|
-
# res.body
|
31
|
-
# # => ["there is", "no try"]
|
32
|
-
|
33
|
-
##
|
34
|
-
# :method: finish
|
35
|
-
#
|
36
|
-
# Returns an array with three elements: the status, headers and body.
|
37
|
-
# If the status is not set, the status is set to 404 if empty body,
|
38
|
-
# otherwise the status is set to 200 and updates the `Content-Type`
|
39
|
-
# header to `text/html`.
|
40
|
-
#
|
41
|
-
# res.status = 200
|
42
|
-
# res.finish
|
43
|
-
# # => [200, {}, []]
|
44
|
-
#
|
45
|
-
# res.status = nil
|
46
|
-
# res.finish
|
47
|
-
# # => [404, {}, []]
|
48
|
-
#
|
49
|
-
# res.status = nil
|
50
|
-
# res.write("yo!")
|
51
|
-
# res.finish
|
52
|
-
# # => [200, { "Content-Type" => "text/html" }, ["yo!"]]
|
53
|
-
|
54
|
-
##
|
55
|
-
# :method: headers
|
56
|
-
#
|
57
|
-
# Returns a hash with the response headers.
|
58
|
-
#
|
59
|
-
# res.headers
|
60
|
-
# # => { "Content-Type" => "text/html", "Content-Length" => "42" }
|
61
|
-
|
62
|
-
##
|
63
|
-
# :method: redirect
|
64
|
-
# :call-seq: redirect(path, 302)
|
65
|
-
#
|
66
|
-
# Sets the `Location` header to `path` and updates the status to
|
67
|
-
# `status`. By default, `status` is `302`.
|
68
|
-
#
|
69
|
-
# res.redirect("/path")
|
70
|
-
#
|
71
|
-
# res["Location"] # => "/path"
|
72
|
-
# res.status # => 302
|
73
|
-
#
|
74
|
-
# res.redirect("http://tynn.ru", 303)
|
75
|
-
#
|
76
|
-
# res["Location"] # => "http://tynn.ru"
|
77
|
-
# res.status # => 303
|
78
|
-
|
79
|
-
##
|
80
|
-
# :method: status
|
81
|
-
#
|
82
|
-
# Returns the status of the response.
|
83
|
-
#
|
84
|
-
# res.status # => 200
|
85
|
-
#
|
86
|
-
|
87
|
-
##
|
88
|
-
# :method: status=
|
89
|
-
# :call-seq: status=(status)
|
90
|
-
#
|
91
|
-
# Sets the status of the response.
|
92
|
-
#
|
93
|
-
# res.status = 200
|
94
|
-
#
|
95
|
-
|
96
|
-
##
|
97
|
-
# :method: write
|
98
|
-
# :call-seq: write(str)
|
99
|
-
#
|
100
|
-
# Appends `str` to `body` and updates the `Content-Length` header.
|
101
|
-
#
|
102
|
-
# res.body # => []
|
103
|
-
#
|
104
|
-
# res.write("foo")
|
105
|
-
# res.write("bar")
|
106
|
-
#
|
107
|
-
# res.body
|
108
|
-
# # => ["foo", "bar"]
|
109
|
-
#
|
110
|
-
# res["Content-Length"]
|
111
|
-
# # => 6
|
112
|
-
end
|
data/examples/composition.ru
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
require_relative "../lib/tynn"
|
2
|
-
|
3
|
-
class Users < Tynn
|
4
|
-
end
|
5
|
-
|
6
|
-
Users.define do
|
7
|
-
on(:id) do |id|
|
8
|
-
get do
|
9
|
-
res.write("GET /users/#{ id }")
|
10
|
-
end
|
11
|
-
|
12
|
-
put do
|
13
|
-
res.write("PUT /users/#{ id }")
|
14
|
-
end
|
15
|
-
|
16
|
-
patch do
|
17
|
-
res.write("PATCH /users/#{ id }")
|
18
|
-
end
|
19
|
-
|
20
|
-
delete do
|
21
|
-
res.write("DELETE /users/#{ id }")
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
get do
|
26
|
-
res.write("GET /users")
|
27
|
-
end
|
28
|
-
|
29
|
-
post do
|
30
|
-
res.write("POST /users")
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
Tynn.define do
|
35
|
-
on("users") do
|
36
|
-
run(Users)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
run(Tynn)
|
data/examples/hello.ru
DELETED
data/examples/protection.ru
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
require_relative "../lib/tynn"
|
2
|
-
require_relative "../lib/tynn/environment"
|
3
|
-
require_relative "../lib/tynn/protection"
|
4
|
-
require_relative "../lib/tynn/session"
|
5
|
-
|
6
|
-
Tynn.helpers(Tynn::Environment)
|
7
|
-
|
8
|
-
Tynn.helpers(Tynn::Protection, ssl: Tynn.production?)
|
9
|
-
|
10
|
-
Tynn.helpers(Tynn::Session, secret: SecureRandom.hex(64))
|
11
|
-
|
12
|
-
Tynn.define do
|
13
|
-
root do
|
14
|
-
res.write("use protection")
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
run(Tynn)
|
data/examples/render.ru
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
require "erb"
|
2
|
-
require_relative "../lib/tynn"
|
3
|
-
require_relative "../lib/tynn/render"
|
4
|
-
|
5
|
-
Tynn.helpers(Tynn::Render, views: File.expand_path("views", __dir__))
|
6
|
-
|
7
|
-
Tynn.define do
|
8
|
-
root do
|
9
|
-
render("home", title: "Thanks for using Tynn!")
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
run(Tynn)
|
data/examples/views/home.erb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
<%= title %>
|
data/examples/views/layout.erb
DELETED
data/lib/tynn/csrf.rb
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
module Tynn::CSRF
|
2
|
-
def csrf
|
3
|
-
@csrf ||= Tynn::CSRF::Helper.new(self)
|
4
|
-
end
|
5
|
-
|
6
|
-
class Helper
|
7
|
-
CSRF_HEADER = "HTTP_X_CSRF_TOKEN".freeze
|
8
|
-
|
9
|
-
def initialize(app)
|
10
|
-
@app = app
|
11
|
-
@req = app.req
|
12
|
-
end
|
13
|
-
|
14
|
-
def token
|
15
|
-
return session[:csrf_token] ||= SecureRandom.base64(32)
|
16
|
-
end
|
17
|
-
|
18
|
-
def reset!
|
19
|
-
session.delete(:csrf_token)
|
20
|
-
end
|
21
|
-
|
22
|
-
def safe?
|
23
|
-
return @req.get? || @req.head? || verify_token
|
24
|
-
end
|
25
|
-
|
26
|
-
def unsafe?
|
27
|
-
return !safe?
|
28
|
-
end
|
29
|
-
|
30
|
-
def form_tag
|
31
|
-
return %Q(<input type="hidden" name="csrf_token" value="#{ token }">)
|
32
|
-
end
|
33
|
-
|
34
|
-
def meta_tag
|
35
|
-
return %Q(<meta name="csrf_token" content="#{ token }">)
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def verify_token
|
41
|
-
return @req[:csrf_token] == token || @req.env[CSRF_HEADER] == token
|
42
|
-
end
|
43
|
-
|
44
|
-
def session
|
45
|
-
return @app.session
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
data/lib/tynn/options.rb
DELETED
data/makefile
DELETED
data/test/csrf_test.rb
DELETED
@@ -1,98 +0,0 @@
|
|
1
|
-
require "securerandom"
|
2
|
-
require_relative "../lib/tynn/csrf"
|
3
|
-
require_relative "../lib/tynn/session"
|
4
|
-
|
5
|
-
setup do
|
6
|
-
Tynn.helpers(Tynn::CSRF)
|
7
|
-
Tynn.helpers(Tynn::Session, secret: SecureRandom.hex(64))
|
8
|
-
|
9
|
-
Tynn::Test.new
|
10
|
-
end
|
11
|
-
|
12
|
-
test "get should be safe" do |app|
|
13
|
-
Tynn.define do
|
14
|
-
get do
|
15
|
-
res.write(csrf.safe?)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
app.get("/")
|
20
|
-
|
21
|
-
assert_equal "true", app.res.body
|
22
|
-
end
|
23
|
-
|
24
|
-
test "head should be safe" do |app|
|
25
|
-
Tynn.define do
|
26
|
-
on req.head? do
|
27
|
-
res.write(csrf.safe?)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
app.head("/")
|
32
|
-
|
33
|
-
assert_equal "true", app.res.body
|
34
|
-
end
|
35
|
-
|
36
|
-
test "invalid csrf token" do |app|
|
37
|
-
Tynn.define do
|
38
|
-
post do
|
39
|
-
res.write(csrf.unsafe?)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
app.post("/")
|
44
|
-
|
45
|
-
assert_equal "true", app.res.body
|
46
|
-
end
|
47
|
-
|
48
|
-
test "valid csrf token" do |app|
|
49
|
-
token = SecureRandom.hex(64)
|
50
|
-
|
51
|
-
Tynn.define do
|
52
|
-
post do
|
53
|
-
session[:csrf_token] = token
|
54
|
-
|
55
|
-
res.write(csrf.safe?)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
app.post("/", csrf_token: token)
|
60
|
-
|
61
|
-
assert_equal "true", app.res.body
|
62
|
-
end
|
63
|
-
|
64
|
-
test "resets token" do |app|
|
65
|
-
token = SecureRandom.hex(64)
|
66
|
-
|
67
|
-
Tynn.define do
|
68
|
-
post do
|
69
|
-
session[:csrf_token] = token
|
70
|
-
|
71
|
-
if csrf.unsafe?
|
72
|
-
csrf.reset!
|
73
|
-
end
|
74
|
-
|
75
|
-
res.write(csrf.token)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
app.post("/", csrf_token: "nonsense")
|
80
|
-
|
81
|
-
assert token != app.res.body
|
82
|
-
end
|
83
|
-
|
84
|
-
test "http header" do |app|
|
85
|
-
token = SecureRandom.hex(64)
|
86
|
-
|
87
|
-
Tynn.define do
|
88
|
-
post do
|
89
|
-
session[:csrf_token] = token
|
90
|
-
|
91
|
-
res.write(csrf.safe?)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
app.post("/", {}, "HTTP_X_CSRF_TOKEN" => token)
|
96
|
-
|
97
|
-
assert_equal "true", app.res.body
|
98
|
-
end
|
data/test/options_test.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
custom / <%= content %>
|
@@ -1 +0,0 @@
|
|
1
|
-
custom / {{! content }}
|
data/test/views/layout.erb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
<%= content %>
|
data/test/views/layout.mote
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
{{! content }}
|
data/test/views/partial.erb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
<%= name %>
|
data/test/views/partial.mote
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
{{ name }}
|
data/test/views/view.erb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
<%= title %> / <%= partial("partial", name: name) %>
|
data/test/views/view.mote
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
{{ title }} / {{! app.partial("partial", name: name) }}
|
data/tynn.gemspec
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
require_relative "lib/tynn/version"
|
2
|
-
|
3
|
-
Gem::Specification.new do |s|
|
4
|
-
s.name = "tynn"
|
5
|
-
s.version = Tynn::VERSION
|
6
|
-
s.summary = "Simple library to create Rack applications"
|
7
|
-
s.description = s.summary
|
8
|
-
s.authors = ["Francesco Rodríguez"]
|
9
|
-
s.email = ["frodsan@protonmail.ch"]
|
10
|
-
s.homepage = "https://github.com/harmoni/tynn"
|
11
|
-
s.license = "MIT"
|
12
|
-
|
13
|
-
s.files = `git ls-files`.split("\n")
|
14
|
-
|
15
|
-
s.add_dependency "rack", "~> 1.6"
|
16
|
-
s.add_dependency "seteable", "1.1.0"
|
17
|
-
s.add_dependency "syro", "~> 1.0"
|
18
|
-
|
19
|
-
s.add_development_dependency "cutest", "1.2.2"
|
20
|
-
s.add_development_dependency "erubis", "~> 2.7"
|
21
|
-
s.add_development_dependency "hmote", "1.4.0"
|
22
|
-
s.add_development_dependency "rack-test", "0.6.3"
|
23
|
-
s.add_development_dependency "tilt", "~> 2.0"
|
24
|
-
end
|