egalite 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.
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/Rakefile +1 -0
- data/egalite.gemspec +24 -0
- data/lib/egalite/auth/basic.rb +32 -0
- data/lib/egalite/blank.rb +53 -0
- data/lib/egalite/errorconsole.rb +77 -0
- data/lib/egalite/helper.rb +251 -0
- data/lib/egalite/keitai/keitai.rb +107 -0
- data/lib/egalite/keitai/ketai.rb +11 -0
- data/lib/egalite/keitai/rack/ketai/carrier/abstract.rb +131 -0
- data/lib/egalite/keitai/rack/ketai/carrier/au.rb +78 -0
- data/lib/egalite/keitai/rack/ketai/carrier/docomo.rb +80 -0
- data/lib/egalite/keitai/rack/ketai/carrier/emoji/ausjisstrtoemojiid.rb +1391 -0
- data/lib/egalite/keitai/rack/ketai/carrier/emoji/docomosjisstrtoemojiid.rb +759 -0
- data/lib/egalite/keitai/rack/ketai/carrier/emoji/emojidata.rb +836 -0
- data/lib/egalite/keitai/rack/ketai/carrier/emoji/softbankutf8strtoemojiid.rb +1119 -0
- data/lib/egalite/keitai/rack/ketai/carrier/emoji/softbankwebcodetoutf8str.rb +499 -0
- data/lib/egalite/keitai/rack/ketai/carrier/iphone.rb +8 -0
- data/lib/egalite/keitai/rack/ketai/carrier/softbank.rb +82 -0
- data/lib/egalite/keitai/rack/ketai/carrier.rb +17 -0
- data/lib/egalite/keitai/rack/ketai/middleware.rb +24 -0
- data/lib/egalite/m17n.rb +193 -0
- data/lib/egalite/route.rb +231 -0
- data/lib/egalite/sendmail.rb +222 -0
- data/lib/egalite/sequel_helper.rb +20 -0
- data/lib/egalite/session.rb +132 -0
- data/lib/egalite/stringify_hash.rb +63 -0
- data/lib/egalite/support.rb +35 -0
- data/lib/egalite/template.rb +287 -0
- data/lib/egalite/version.rb +3 -0
- data/lib/egalite.rb +744 -0
- metadata +35 -3
@@ -0,0 +1,132 @@
|
|
1
|
+
|
2
|
+
require 'openssl'
|
3
|
+
|
4
|
+
module Egalite
|
5
|
+
class Session
|
6
|
+
attr_accessor :expire_after, :hash, :cookie_name
|
7
|
+
|
8
|
+
def initialize(env, cookies, opts = {})
|
9
|
+
@env = env
|
10
|
+
@cookies = cookies
|
11
|
+
@cookie_name = opts[:cookie_name] || 'egalite_session'
|
12
|
+
@expire_after = opts[:expire_after] || (86400 * 30)
|
13
|
+
@secure = opts[:secure] || false
|
14
|
+
@path = opts[:path] || '/'
|
15
|
+
@hash = {}
|
16
|
+
@loaded = false
|
17
|
+
end
|
18
|
+
def create
|
19
|
+
raise NotImplementedError
|
20
|
+
end
|
21
|
+
def load
|
22
|
+
raise NotImplementedError
|
23
|
+
end
|
24
|
+
def save
|
25
|
+
raise NotImplementedError
|
26
|
+
end
|
27
|
+
def delete
|
28
|
+
raise NotImplementedError
|
29
|
+
end
|
30
|
+
def [](k)
|
31
|
+
@hash[k]
|
32
|
+
end
|
33
|
+
def []=(k,v)
|
34
|
+
@hash[k] = v
|
35
|
+
end
|
36
|
+
end
|
37
|
+
class SessionSequel < Session
|
38
|
+
def self.create_table(db, opts = {})
|
39
|
+
table = opts[:table_name] || :sessions
|
40
|
+
|
41
|
+
db.create_table(table) {
|
42
|
+
primary_key :id, :integer, :auto_increment => true
|
43
|
+
column :mac, :varchar
|
44
|
+
column :updated_at, :timestamp
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize(env, cookies, opts = {})
|
49
|
+
@db = env.db
|
50
|
+
@table = opts[:tablename] || :sessions
|
51
|
+
|
52
|
+
super(env, cookies, opts)
|
53
|
+
end
|
54
|
+
def cookie
|
55
|
+
{
|
56
|
+
:value => @sstr,
|
57
|
+
:expires => Time.now + @expire_after,
|
58
|
+
:path => @path,
|
59
|
+
:secure => @secure
|
60
|
+
}
|
61
|
+
end
|
62
|
+
def sstr
|
63
|
+
@sstr
|
64
|
+
end
|
65
|
+
def _load(_sstr)
|
66
|
+
return false unless _sstr and _sstr.size > 0
|
67
|
+
(sid,mac) = _sstr.split(/_/)
|
68
|
+
|
69
|
+
sid = sid.to_i
|
70
|
+
return false if sid <= 0
|
71
|
+
return false unless mac and mac.size > 0
|
72
|
+
|
73
|
+
rec = @db[@table][:id => sid]
|
74
|
+
return false unless rec and rec[:mac] == mac
|
75
|
+
|
76
|
+
# timeout check
|
77
|
+
updated = rec[:updated_at]
|
78
|
+
return false if Time.now > (updated + @expire_after)
|
79
|
+
|
80
|
+
@sstr = _sstr
|
81
|
+
@hash = rec
|
82
|
+
@sid = sid
|
83
|
+
@mac = mac
|
84
|
+
@loaded = true
|
85
|
+
@cookies[@cookie_name] = cookie
|
86
|
+
|
87
|
+
@db[@table].filter(:id => sid).update(:updated_at => 'now')
|
88
|
+
|
89
|
+
true
|
90
|
+
end
|
91
|
+
def load_from_param(_sstr)
|
92
|
+
_load(_sstr)
|
93
|
+
end
|
94
|
+
def load
|
95
|
+
_sstr = @cookies[@cookie_name]
|
96
|
+
_sstr = _sstr[0] if _sstr.is_a?(Array)
|
97
|
+
_load(_sstr)
|
98
|
+
end
|
99
|
+
def create(hash = nil)
|
100
|
+
@sid = @db[@table].insert({})
|
101
|
+
@mac = OpenSSL::Random.random_bytes(8).unpack('h*')[0]
|
102
|
+
hash ||= {}
|
103
|
+
@db[@table].filter(:id => @sid).update(hash.merge(:mac => @mac,:updated_at => Time.now))
|
104
|
+
@hash = @db[@table][:id => @sid]
|
105
|
+
|
106
|
+
@sstr = "#@sid" + "_#@mac"
|
107
|
+
@cookies[@cookie_name] = cookie
|
108
|
+
@loaded = true
|
109
|
+
|
110
|
+
true
|
111
|
+
end
|
112
|
+
def delete
|
113
|
+
@cookies[@cookie_name] = {
|
114
|
+
:value => nil,
|
115
|
+
:expires => Time.now - 3600,
|
116
|
+
:path => @path,
|
117
|
+
:secure => @secure
|
118
|
+
}
|
119
|
+
@db[@table].filter(:id => @sid).delete
|
120
|
+
@loaded = false
|
121
|
+
true
|
122
|
+
end
|
123
|
+
def save
|
124
|
+
return false unless @loaded
|
125
|
+
[:updated_at, :mac, :id].each { |s| @hash.delete(s) }
|
126
|
+
@db[@table].filter(:id => @sid).update(
|
127
|
+
{:updated_at => Time.now}.merge(@hash)
|
128
|
+
)
|
129
|
+
true
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end # module
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# used with http parameters
|
2
|
+
# simpler version of HashWithIndifferentAccess of Ruby on Rails
|
3
|
+
|
4
|
+
module Egalite
|
5
|
+
class StringifyHash < Hash
|
6
|
+
def self.create(values)
|
7
|
+
hash = self.new
|
8
|
+
hash.update(values)
|
9
|
+
hash
|
10
|
+
end
|
11
|
+
def [](k)
|
12
|
+
super(stringify(k))
|
13
|
+
end
|
14
|
+
def []=(k,v)
|
15
|
+
super(stringify(k),v)
|
16
|
+
end
|
17
|
+
def update(hash)
|
18
|
+
newhash = {}
|
19
|
+
hash.each { |k,v|
|
20
|
+
newhash[stringify(k)] = v
|
21
|
+
}
|
22
|
+
super(newhash)
|
23
|
+
end
|
24
|
+
alias_method :merge!, :update
|
25
|
+
|
26
|
+
def key?(key)
|
27
|
+
super(stringify(key))
|
28
|
+
end
|
29
|
+
|
30
|
+
alias_method :include?, :key?
|
31
|
+
alias_method :has_key?, :key?
|
32
|
+
alias_method :member?, :key?
|
33
|
+
|
34
|
+
def fetch(key, *extras)
|
35
|
+
super(stringify(key), *extras)
|
36
|
+
end
|
37
|
+
|
38
|
+
def values_at(*indices)
|
39
|
+
indices.collect {|key| self[key]}
|
40
|
+
end
|
41
|
+
|
42
|
+
def dup
|
43
|
+
StringifyHash.create(self)
|
44
|
+
end
|
45
|
+
|
46
|
+
def merge(hash)
|
47
|
+
dup.update(hash)
|
48
|
+
end
|
49
|
+
|
50
|
+
def delete(key)
|
51
|
+
super(stringify(key))
|
52
|
+
end
|
53
|
+
|
54
|
+
# Convert to a Hash with String keys.
|
55
|
+
def to_hash
|
56
|
+
Hash.new(default).merge(self)
|
57
|
+
end
|
58
|
+
private
|
59
|
+
def stringify(key)
|
60
|
+
key.kind_of?(Symbol) ? key.to_s : key
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Egalite support methods
|
2
|
+
|
3
|
+
class Hash
|
4
|
+
def <<(b)
|
5
|
+
merge(b.to_hash)
|
6
|
+
end
|
7
|
+
def >>(b)
|
8
|
+
b.to_hash.merge(self)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class NilClass #:nodoc:
|
13
|
+
def size
|
14
|
+
0
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# <<from ActiveSupport library of Ruby on Rails>>
|
19
|
+
# (MIT License)
|
20
|
+
|
21
|
+
# Tries to send the method only if object responds to it. Return +nil+ otherwise.
|
22
|
+
#
|
23
|
+
# ==== Example :
|
24
|
+
#
|
25
|
+
# # Without try
|
26
|
+
# @person ? @person.name : nil
|
27
|
+
#
|
28
|
+
# With try
|
29
|
+
# @person.try(:name)
|
30
|
+
class Object
|
31
|
+
def try(method)
|
32
|
+
send(method) if respond_to?(method, true)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,287 @@
|
|
1
|
+
require 'jcode'
|
2
|
+
|
3
|
+
module Egalite
|
4
|
+
|
5
|
+
class NonEscapeString < String
|
6
|
+
def +(b)
|
7
|
+
NonEscapeString.new(super(HTMLTagBuilder.escape_html(b)))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class HTMLTemplate
|
12
|
+
RE_NEST = /<(group|if|unless)\s+name=['"](.+?)['"]>/i
|
13
|
+
RE_ENDNEST = /<\/(group|if|unless)>/i
|
14
|
+
RE_PLACE = /&=([.-_0-9a-zA-Z]+?);/
|
15
|
+
RE_INPUT = /<input\s+(.+?)>/im
|
16
|
+
RE_SELECT = /<select\s+name\s*=\s*['"](.+?)['"](.*?)>\s*<\/select>/im
|
17
|
+
|
18
|
+
RE_A = /<a\s+(.+?)>/im
|
19
|
+
RE_FORM = /<form\s+(.+?)>/im
|
20
|
+
|
21
|
+
RE_INCLUDE = /<include\s+(.+?)\/>/i
|
22
|
+
RE_PARENT = /<parent\s+name=['"](.+?)['"]\s*\/>/i
|
23
|
+
RE_YIELD = /<yield\/>/i
|
24
|
+
|
25
|
+
attr_accessor :controller, :default_escape
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@default_escape = true
|
29
|
+
@controller = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def parse_tag_attributes(attrs)
|
35
|
+
a = attrs.split(/(\:?\w+(!:[^=])|\:?\w+=(?:'[^']+'|"[^"]+"|\S+))\s*/)
|
36
|
+
a = a.select { |s| s != "" }
|
37
|
+
hash = {}
|
38
|
+
a.each { |s|
|
39
|
+
b = s.split('=',2)
|
40
|
+
b[0].sub!(/\s$/,'')
|
41
|
+
b[1] = b[1][1..-2] if b[1] and (b[1][0,1] == '"' or b[1][0,1] == "'")
|
42
|
+
hash[b[0]] = b[1] || true
|
43
|
+
}
|
44
|
+
hash
|
45
|
+
end
|
46
|
+
def attr_colon(attrs)
|
47
|
+
colons = {}
|
48
|
+
attrs.each { |k,v| colons[k[1..-1]] = v if k =~ /^\:/ }
|
49
|
+
str = attrs.select { |k,v| k !~ /^\:/ }.map { |k,v| "#{k}='#{v}'" }.join(' ')
|
50
|
+
[colons, str]
|
51
|
+
end
|
52
|
+
|
53
|
+
def dotchain(values, name)
|
54
|
+
dots = name.split('.').select {|s| not s.empty? }
|
55
|
+
|
56
|
+
value = values
|
57
|
+
dots.each { |key|
|
58
|
+
value = if not value.is_a?(Hash) and value.respond_to?(key)
|
59
|
+
value.send(key)
|
60
|
+
elsif value.respond_to?(:[])
|
61
|
+
value[key] || value[key.to_sym]
|
62
|
+
end
|
63
|
+
break unless value
|
64
|
+
}
|
65
|
+
value
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# tags
|
70
|
+
#
|
71
|
+
def placeholder(html, params)
|
72
|
+
html.gsub!(RE_PLACE) {
|
73
|
+
key = $1
|
74
|
+
if params[key].is_a?(NonEscapeString) or not @default_escape
|
75
|
+
params[key]
|
76
|
+
else
|
77
|
+
escapeHTML(params[key])
|
78
|
+
end
|
79
|
+
}
|
80
|
+
end
|
81
|
+
def input_tag(html, params)
|
82
|
+
html.gsub!(RE_INPUT) { |s|
|
83
|
+
attrs = parse_tag_attributes($1)
|
84
|
+
next s if attrs['checked'] or attrs['selected']
|
85
|
+
name = attrs['name']
|
86
|
+
next s unless name
|
87
|
+
case attrs['type']
|
88
|
+
when 'text'
|
89
|
+
next s if attrs['value']
|
90
|
+
s.sub!(/\/?>$/," value='"+escapeHTML(params[name])+"'/>") if params[name]
|
91
|
+
when 'hidden'
|
92
|
+
next s if attrs['value']
|
93
|
+
s.sub!(/\/?>$/," value='"+escapeHTML(params[name])+"'/>") if params[name]
|
94
|
+
when 'radio'
|
95
|
+
s.sub!(/\/?>$/," checked/>") if (params[name].to_s == attrs['value'])
|
96
|
+
when 'checkbox'
|
97
|
+
s.sub!(/\/?>$/," checked/>") if params[name]
|
98
|
+
end
|
99
|
+
s
|
100
|
+
}
|
101
|
+
end
|
102
|
+
def a_tag(html, params)
|
103
|
+
html.gsub!(RE_A) { |s|
|
104
|
+
attrs = parse_tag_attributes($1)
|
105
|
+
next s if attrs['href']
|
106
|
+
next s unless @controller
|
107
|
+
|
108
|
+
(colons, noncolons) = attr_colon(attrs)
|
109
|
+
next s if colons.empty?
|
110
|
+
# when :hoge=$foo, expand hash parameter ['foo']
|
111
|
+
colons.each { |k,v|
|
112
|
+
next if v[0,1] != '$'
|
113
|
+
val = params[v[1..-1]]
|
114
|
+
colons[k] = val
|
115
|
+
}
|
116
|
+
colons = StringifyHash.create(colons)
|
117
|
+
link = @controller.url_for(colons)
|
118
|
+
"<a href='#{link}' #{noncolons}>"
|
119
|
+
}
|
120
|
+
end
|
121
|
+
def form_tag(html,params)
|
122
|
+
html.gsub!(RE_FORM) { |s|
|
123
|
+
attrs = parse_tag_attributes($1)
|
124
|
+
next s if attrs['action']
|
125
|
+
next s unless @controller
|
126
|
+
|
127
|
+
(colons, noncolons) = attr_colon(attrs)
|
128
|
+
next s if colons.empty?
|
129
|
+
colons = StringifyHash.create(colons)
|
130
|
+
link = @controller.url_for(colons)
|
131
|
+
"<form action='#{link}' #{noncolons}>"
|
132
|
+
}
|
133
|
+
end
|
134
|
+
def select_tag(html,params)
|
135
|
+
html.gsub!(RE_SELECT) { sel = "<select name='#$1'#$2>"
|
136
|
+
if (params[$1] and params[$1].is_a?(Array))
|
137
|
+
params[$1].each_index() { |key|
|
138
|
+
next if (key == 0)
|
139
|
+
selected = " selected" if params[$1][0] == key
|
140
|
+
value = params[$1][key]
|
141
|
+
sel << "<option value='#{key}'#{selected}>"
|
142
|
+
sel << escapeHTML(value)
|
143
|
+
sel << "</option>" unless @keitai
|
144
|
+
}
|
145
|
+
end
|
146
|
+
sel << "</select>"
|
147
|
+
}
|
148
|
+
end
|
149
|
+
|
150
|
+
#
|
151
|
+
# main routines
|
152
|
+
#
|
153
|
+
|
154
|
+
def nonnestedtags(html, params)
|
155
|
+
placeholder(html,params)
|
156
|
+
input_tag(html,params)
|
157
|
+
a_tag(html,params)
|
158
|
+
form_tag(html,params)
|
159
|
+
select_tag(html,params)
|
160
|
+
|
161
|
+
# parse include tag
|
162
|
+
if block_given?
|
163
|
+
html.gsub!(RE_INCLUDE) {
|
164
|
+
attrs = parse_tag_attributes($1)
|
165
|
+
attrs.each { |k,v| attrs[k[1..-1]] = v if k =~ /^\:/ }
|
166
|
+
yield(attrs)
|
167
|
+
}
|
168
|
+
parent = nil
|
169
|
+
md = RE_PARENT.match(html)
|
170
|
+
parent = md[1] if md
|
171
|
+
html.gsub!(RE_PARENT,"")
|
172
|
+
if parent
|
173
|
+
txt = yield(parent)
|
174
|
+
txt.gsub!(RE_YIELD, html)
|
175
|
+
html = txt
|
176
|
+
end
|
177
|
+
end
|
178
|
+
html
|
179
|
+
end
|
180
|
+
|
181
|
+
def keyexpander(params, parent_params)
|
182
|
+
lambda { |k|
|
183
|
+
if k[0,1] == '.'
|
184
|
+
dotchain(params, k)
|
185
|
+
else
|
186
|
+
if params[k] == nil
|
187
|
+
if params[k.to_sym] == nil
|
188
|
+
parent_params[k]
|
189
|
+
else
|
190
|
+
params[k.to_sym]
|
191
|
+
end
|
192
|
+
else
|
193
|
+
params[k]
|
194
|
+
end
|
195
|
+
end
|
196
|
+
}
|
197
|
+
end
|
198
|
+
|
199
|
+
def string_after_outermost_closetag(html)
|
200
|
+
while md1 = RE_NEST.match(html)
|
201
|
+
break if (RE_ENDNEST.match(md1.pre_match))
|
202
|
+
html = string_after_outermost_closetag(md1.post_match)
|
203
|
+
end
|
204
|
+
RE_ENDNEST.match(html).post_match
|
205
|
+
end
|
206
|
+
|
207
|
+
public
|
208
|
+
|
209
|
+
def escapeHTML(s)
|
210
|
+
s.to_s.gsub(/&/n, '&').gsub(/'/n,''').gsub(/\"/n, '"').gsub(/>/n, '>').gsub(/</n, '<')
|
211
|
+
end
|
212
|
+
|
213
|
+
def handleTemplate(html, orig_values, parent_params={}, &block)
|
214
|
+
params = keyexpander(orig_values, parent_params)
|
215
|
+
|
216
|
+
# parse group tag and recurse inner loop
|
217
|
+
while md1 = RE_NEST.match(html) # beware: complicated....
|
218
|
+
# break if it is innermost loop.
|
219
|
+
break if (RE_ENDNEST.match(md1.pre_match))
|
220
|
+
|
221
|
+
# obtain a length of outermost group tag.
|
222
|
+
post = string_after_outermost_closetag(md1.post_match)
|
223
|
+
|
224
|
+
tag = md1[1]
|
225
|
+
key = md1[2]
|
226
|
+
|
227
|
+
# recursive-call for each element of array
|
228
|
+
innertext = ""
|
229
|
+
case tag.downcase
|
230
|
+
when 'group'
|
231
|
+
groupval = params[key]
|
232
|
+
groupval = [] if (groupval == nil)
|
233
|
+
groupval = [groupval] unless (groupval.is_a?(Array))
|
234
|
+
groupval.each { |v|
|
235
|
+
innertext << handleTemplate(md1.post_match, v, params)
|
236
|
+
}
|
237
|
+
when 'if'
|
238
|
+
unless params[key].blank?
|
239
|
+
innertext << handleTemplate(md1.post_match, orig_values, parent_params)
|
240
|
+
end
|
241
|
+
when 'unless'
|
242
|
+
if params[key].blank?
|
243
|
+
innertext << handleTemplate(md1.post_match, orig_values, parent_params)
|
244
|
+
end
|
245
|
+
else
|
246
|
+
raise
|
247
|
+
end
|
248
|
+
# replace this group tag
|
249
|
+
html[md1.begin(0)..-(post.size+1)] = innertext
|
250
|
+
end
|
251
|
+
# cutoff after end tag, in inner-most loop.
|
252
|
+
md1 = RE_ENDNEST.match(html)
|
253
|
+
html = md1.pre_match if (md1)
|
254
|
+
|
255
|
+
nonnestedtags(html, params, &block)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
class CSRFTemplate < HTMLTemplate
|
260
|
+
RE_FORM = /<form\s+([^>]+?)>(?!\s*<input type='hidden' name='csrf')/im
|
261
|
+
|
262
|
+
def form_tag(html,params)
|
263
|
+
html.gsub!(RE_FORM) { |s|
|
264
|
+
formtag = s
|
265
|
+
attrs = parse_tag_attributes($1)
|
266
|
+
csrf = nil
|
267
|
+
if attrs[":nocsrf"]
|
268
|
+
attrs.delete(":nocsrf")
|
269
|
+
elsif attrs["method"] =~ /\APOST\Z/i
|
270
|
+
csrf = params["csrf"]
|
271
|
+
csrf = "<input type='hidden' name='csrf' value='#{escapeHTML(csrf)}'/>"
|
272
|
+
end
|
273
|
+
|
274
|
+
if (not attrs['action']) and @controller
|
275
|
+
(colons, noncolons) = attr_colon(attrs)
|
276
|
+
unless colons.empty?
|
277
|
+
colons = StringifyHash.create(colons)
|
278
|
+
link = @controller.url_for(colons)
|
279
|
+
formtag = "<form action='#{link}' #{noncolons}>"
|
280
|
+
end
|
281
|
+
end
|
282
|
+
"#{formtag}#{csrf}"
|
283
|
+
}
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
end # end module
|