powerhome-activeldap 3.2.3
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 +7 -0
- data/.yardopts +6 -0
- data/COPYING +340 -0
- data/Gemfile +12 -0
- data/LICENSE +59 -0
- data/README.textile +140 -0
- data/TODO +32 -0
- data/benchmark/README.md +64 -0
- data/benchmark/bench-backend.rb +247 -0
- data/benchmark/bench-instantiate.rb +98 -0
- data/benchmark/config.yaml.sample +5 -0
- data/doc/text/development.textile +54 -0
- data/doc/text/news.textile +811 -0
- data/doc/text/rails.textile +144 -0
- data/doc/text/tutorial.textile +1010 -0
- data/examples/config.yaml.example +5 -0
- data/examples/example.der +0 -0
- data/examples/example.jpg +0 -0
- data/examples/groupadd +41 -0
- data/examples/groupdel +35 -0
- data/examples/groupls +49 -0
- data/examples/groupmod +42 -0
- data/examples/lpasswd +55 -0
- data/examples/objects/group.rb +13 -0
- data/examples/objects/ou.rb +4 -0
- data/examples/objects/user.rb +20 -0
- data/examples/ouadd +38 -0
- data/examples/useradd +45 -0
- data/examples/useradd-binary +53 -0
- data/examples/userdel +34 -0
- data/examples/userls +50 -0
- data/examples/usermod +42 -0
- data/examples/usermod-binary-add +50 -0
- data/examples/usermod-binary-add-time +54 -0
- data/examples/usermod-binary-del +48 -0
- data/examples/usermod-lang-add +43 -0
- data/lib/active_ldap.rb +85 -0
- data/lib/active_ldap/action_controller/ldap_benchmarking.rb +55 -0
- data/lib/active_ldap/acts/tree.rb +78 -0
- data/lib/active_ldap/adapter/base.rb +707 -0
- data/lib/active_ldap/adapter/jndi.rb +184 -0
- data/lib/active_ldap/adapter/jndi_connection.rb +185 -0
- data/lib/active_ldap/adapter/ldap.rb +290 -0
- data/lib/active_ldap/adapter/ldap_ext.rb +105 -0
- data/lib/active_ldap/adapter/net_ldap.rb +309 -0
- data/lib/active_ldap/adapter/net_ldap_ext.rb +23 -0
- data/lib/active_ldap/association/belongs_to.rb +47 -0
- data/lib/active_ldap/association/belongs_to_many.rb +58 -0
- data/lib/active_ldap/association/children.rb +21 -0
- data/lib/active_ldap/association/collection.rb +105 -0
- data/lib/active_ldap/association/has_many.rb +31 -0
- data/lib/active_ldap/association/has_many_utils.rb +44 -0
- data/lib/active_ldap/association/has_many_wrap.rb +75 -0
- data/lib/active_ldap/association/proxy.rb +107 -0
- data/lib/active_ldap/associations.rb +205 -0
- data/lib/active_ldap/attribute_methods.rb +23 -0
- data/lib/active_ldap/attribute_methods/before_type_cast.rb +24 -0
- data/lib/active_ldap/attribute_methods/dirty.rb +43 -0
- data/lib/active_ldap/attribute_methods/query.rb +31 -0
- data/lib/active_ldap/attribute_methods/read.rb +44 -0
- data/lib/active_ldap/attribute_methods/write.rb +38 -0
- data/lib/active_ldap/attributes.rb +176 -0
- data/lib/active_ldap/base.rb +1410 -0
- data/lib/active_ldap/callbacks.rb +71 -0
- data/lib/active_ldap/command.rb +49 -0
- data/lib/active_ldap/compatible.rb +44 -0
- data/lib/active_ldap/configuration.rb +147 -0
- data/lib/active_ldap/connection.rb +299 -0
- data/lib/active_ldap/distinguished_name.rb +291 -0
- data/lib/active_ldap/entry_attribute.rb +78 -0
- data/lib/active_ldap/escape.rb +12 -0
- data/lib/active_ldap/get_text.rb +20 -0
- data/lib/active_ldap/get_text/parser.rb +161 -0
- data/lib/active_ldap/helper.rb +92 -0
- data/lib/active_ldap/human_readable.rb +133 -0
- data/lib/active_ldap/ldap_error.rb +74 -0
- data/lib/active_ldap/ldif.rb +930 -0
- data/lib/active_ldap/log_subscriber.rb +50 -0
- data/lib/active_ldap/object_class.rb +95 -0
- data/lib/active_ldap/operations.rb +624 -0
- data/lib/active_ldap/persistence.rb +100 -0
- data/lib/active_ldap/populate.rb +53 -0
- data/lib/active_ldap/railtie.rb +43 -0
- data/lib/active_ldap/railties/controller_runtime.rb +48 -0
- data/lib/active_ldap/schema.rb +701 -0
- data/lib/active_ldap/schema/syntaxes.rb +422 -0
- data/lib/active_ldap/timeout.rb +75 -0
- data/lib/active_ldap/timeout_stub.rb +17 -0
- data/lib/active_ldap/user_password.rb +99 -0
- data/lib/active_ldap/validations.rb +200 -0
- data/lib/active_ldap/version.rb +3 -0
- data/lib/active_ldap/xml.rb +139 -0
- data/lib/rails/generators/active_ldap/model/USAGE +18 -0
- data/lib/rails/generators/active_ldap/model/model_generator.rb +47 -0
- data/lib/rails/generators/active_ldap/model/templates/model_active_ldap.rb +3 -0
- data/lib/rails/generators/active_ldap/scaffold/scaffold_generator.rb +14 -0
- data/lib/rails/generators/active_ldap/scaffold/templates/ldap.yml +19 -0
- data/po/en/active-ldap.po +4029 -0
- data/po/ja/active-ldap.po +4060 -0
- data/test/add-phonetic-attribute-options-to-slapd.ldif +10 -0
- data/test/al-test-utils.rb +428 -0
- data/test/command.rb +111 -0
- data/test/config.yaml.sample +6 -0
- data/test/fixtures/lower_case_object_class_schema.rb +802 -0
- data/test/run-test.rb +34 -0
- data/test/test_acts_as_tree.rb +60 -0
- data/test/test_adapter.rb +121 -0
- data/test/test_associations.rb +701 -0
- data/test/test_attributes.rb +117 -0
- data/test/test_base.rb +1214 -0
- data/test/test_base_per_instance.rb +61 -0
- data/test/test_bind.rb +62 -0
- data/test/test_callback.rb +31 -0
- data/test/test_configuration.rb +40 -0
- data/test/test_connection.rb +82 -0
- data/test/test_connection_per_class.rb +112 -0
- data/test/test_connection_per_dn.rb +112 -0
- data/test/test_dirty.rb +98 -0
- data/test/test_dn.rb +172 -0
- data/test/test_find.rb +176 -0
- data/test/test_groupadd.rb +50 -0
- data/test/test_groupdel.rb +46 -0
- data/test/test_groupls.rb +107 -0
- data/test/test_groupmod.rb +51 -0
- data/test/test_ldif.rb +1890 -0
- data/test/test_load.rb +133 -0
- data/test/test_lpasswd.rb +75 -0
- data/test/test_object_class.rb +74 -0
- data/test/test_persistence.rb +131 -0
- data/test/test_reflection.rb +175 -0
- data/test/test_schema.rb +559 -0
- data/test/test_syntax.rb +444 -0
- data/test/test_user.rb +217 -0
- data/test/test_user_password.rb +108 -0
- data/test/test_useradd-binary.rb +62 -0
- data/test/test_useradd.rb +57 -0
- data/test/test_userdel.rb +48 -0
- data/test/test_userls.rb +91 -0
- data/test/test_usermod-binary-add-time.rb +65 -0
- data/test/test_usermod-binary-add.rb +64 -0
- data/test/test_usermod-binary-del.rb +66 -0
- data/test/test_usermod-lang-add.rb +59 -0
- data/test/test_usermod.rb +58 -0
- data/test/test_validation.rb +274 -0
- metadata +379 -0
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
module ActiveLdap
|
|
2
|
+
class Schema
|
|
3
|
+
module Syntaxes
|
|
4
|
+
class << self
|
|
5
|
+
def [](id)
|
|
6
|
+
syntax = Base::SYNTAXES[id]
|
|
7
|
+
if syntax
|
|
8
|
+
syntax.new
|
|
9
|
+
else
|
|
10
|
+
nil
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class Base
|
|
16
|
+
include GetTextSupport
|
|
17
|
+
SYNTAXES = {}
|
|
18
|
+
|
|
19
|
+
printable_character_source = "a-zA-Z\\d\"()+,\\-.\\/:? "
|
|
20
|
+
PRINTABLE_CHARACTER = /[#{printable_character_source}]/ #
|
|
21
|
+
UNPRINTABLE_CHARACTER = /[^#{printable_character_source}]/ #
|
|
22
|
+
|
|
23
|
+
def type_cast(value)
|
|
24
|
+
value
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def valid?(value)
|
|
28
|
+
validate(value).nil?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def validate(value)
|
|
32
|
+
validate_normalized_value(normalize_value(value), value)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def normalize_value(value)
|
|
36
|
+
value
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class BitString < Base
|
|
41
|
+
SYNTAXES["1.3.6.1.4.1.1466.115.121.1.6"] = self
|
|
42
|
+
|
|
43
|
+
def type_cast(value)
|
|
44
|
+
return nil if value.nil?
|
|
45
|
+
if /\A'([01]*)'B\z/ =~ value.to_s
|
|
46
|
+
$1
|
|
47
|
+
else
|
|
48
|
+
value
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def normalize_value(value)
|
|
53
|
+
if value.is_a?(String) and /\A[01]*\z/ =~ value
|
|
54
|
+
"'#{value}'B"
|
|
55
|
+
else
|
|
56
|
+
value
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
def validate_normalized_value(value, original_value)
|
|
62
|
+
if /\A'/ !~ value
|
|
63
|
+
return _("%s doesn't have the first \"'\"") % original_value.inspect
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
if /'B\z/ !~ value
|
|
67
|
+
return _("%s doesn't have the last \"'B\"") % original_value.inspect
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
if /([^01])/ =~ value[1..-3]
|
|
71
|
+
return _("%s has invalid character '%s'") % [value.inspect, $1]
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
nil
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
class Boolean < Base
|
|
79
|
+
SYNTAXES["1.3.6.1.4.1.1466.115.121.1.7"] = self
|
|
80
|
+
|
|
81
|
+
def type_cast(value)
|
|
82
|
+
case value
|
|
83
|
+
when "TRUE"
|
|
84
|
+
true
|
|
85
|
+
when "FALSE"
|
|
86
|
+
false
|
|
87
|
+
else
|
|
88
|
+
value
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def normalize_value(value)
|
|
93
|
+
case value
|
|
94
|
+
when true, "1"
|
|
95
|
+
"TRUE"
|
|
96
|
+
when false, "0"
|
|
97
|
+
"FALSE"
|
|
98
|
+
else
|
|
99
|
+
value
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
private
|
|
104
|
+
def validate_normalized_value(value, original_value)
|
|
105
|
+
if %w(TRUE FALSE).include?(value)
|
|
106
|
+
nil
|
|
107
|
+
else
|
|
108
|
+
_("%s should be TRUE or FALSE") % original_value.inspect
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
class CountryString < Base
|
|
114
|
+
SYNTAXES["1.3.6.1.4.1.1466.115.121.1.11"] = self
|
|
115
|
+
|
|
116
|
+
private
|
|
117
|
+
def validate_normalized_value(value, original_value)
|
|
118
|
+
if /\A#{PRINTABLE_CHARACTER}{2,2}\z/i =~ value
|
|
119
|
+
nil
|
|
120
|
+
else
|
|
121
|
+
format = _("%s should be just 2 printable characters")
|
|
122
|
+
format % original_value.inspect
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
class DistinguishedName < Base
|
|
128
|
+
SYNTAXES["1.3.6.1.4.1.1466.115.121.1.12"] = self
|
|
129
|
+
|
|
130
|
+
def type_cast(value)
|
|
131
|
+
return nil if value.nil?
|
|
132
|
+
DN.parse(value)
|
|
133
|
+
rescue DistinguishedNameInvalid
|
|
134
|
+
value
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def normalize_value(value)
|
|
138
|
+
if value.is_a?(DN)
|
|
139
|
+
value.to_s
|
|
140
|
+
else
|
|
141
|
+
value
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
private
|
|
146
|
+
def validate_normalized_value(value, original_value)
|
|
147
|
+
DN.parse(value)
|
|
148
|
+
nil
|
|
149
|
+
rescue DistinguishedNameInvalid
|
|
150
|
+
$!.message
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
class DirectoryString < Base
|
|
155
|
+
SYNTAXES["1.3.6.1.4.1.1466.115.121.1.15"] = self
|
|
156
|
+
|
|
157
|
+
private
|
|
158
|
+
def validate_normalized_value(value, original_value)
|
|
159
|
+
value.unpack("U*")
|
|
160
|
+
nil
|
|
161
|
+
rescue ArgumentError
|
|
162
|
+
_("%s has invalid UTF-8 character") % original_value.inspect
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
class GeneralizedTime < Base
|
|
167
|
+
SYNTAXES["1.3.6.1.4.1.1466.115.121.1.24"] = self
|
|
168
|
+
FORMAT = /\A
|
|
169
|
+
(\d{4,4})?
|
|
170
|
+
(\d{2,2})?
|
|
171
|
+
(\d{2,2})?
|
|
172
|
+
(\d{2,2})?
|
|
173
|
+
(\d{2,2})?
|
|
174
|
+
(\d{2,2})?
|
|
175
|
+
([,.]\d+)?
|
|
176
|
+
([+-]\d{4,4}|Z)?
|
|
177
|
+
\z/x
|
|
178
|
+
|
|
179
|
+
def type_cast(value)
|
|
180
|
+
return value if value.nil? or value.is_a?(Time)
|
|
181
|
+
match_data = FORMAT.match(value)
|
|
182
|
+
if match_data
|
|
183
|
+
required_components = match_data.to_a[1, 5]
|
|
184
|
+
return value if required_components.any?(&:nil?)
|
|
185
|
+
year, month, day, hour, minute = required_components.collect(&:to_i)
|
|
186
|
+
second = match_data[-3].to_i
|
|
187
|
+
fraction = match_data[-2]
|
|
188
|
+
fraction = fraction.to_f if fraction
|
|
189
|
+
time_zone = match_data[-1]
|
|
190
|
+
arguments = [
|
|
191
|
+
year, month, day, hour, minute, second, fraction, time_zone,
|
|
192
|
+
Time.now
|
|
193
|
+
]
|
|
194
|
+
if Time.method(:make_time).arity == 10
|
|
195
|
+
arguments.unshift(value)
|
|
196
|
+
end
|
|
197
|
+
begin
|
|
198
|
+
Time.send(:make_time, *arguments)
|
|
199
|
+
rescue ArgumentError
|
|
200
|
+
raise if year >= 1700
|
|
201
|
+
out_of_range_messages = ["argument out of range",
|
|
202
|
+
"time out of range"]
|
|
203
|
+
raise unless out_of_range_messages.include?($!.message)
|
|
204
|
+
Time.at(0)
|
|
205
|
+
rescue RangeError
|
|
206
|
+
raise if year >= 1700
|
|
207
|
+
raise if $!.message != "bignum too big to convert into `long'"
|
|
208
|
+
Time.at(0)
|
|
209
|
+
end
|
|
210
|
+
else
|
|
211
|
+
value
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def normalize_value(value)
|
|
216
|
+
if value.is_a?(Time)
|
|
217
|
+
normalized_value = value.strftime("%Y%m%d%H%M%S")
|
|
218
|
+
if value.gmt?
|
|
219
|
+
normalized_value + "Z"
|
|
220
|
+
else
|
|
221
|
+
normalized_value + ("%+03d%02d" % value.gmtoff.divmod(3600))
|
|
222
|
+
end
|
|
223
|
+
else
|
|
224
|
+
value
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
private
|
|
229
|
+
def validate_normalized_value(value, original_value)
|
|
230
|
+
match_data = FORMAT.match(value)
|
|
231
|
+
if match_data
|
|
232
|
+
date_data = match_data.to_a[1..-1]
|
|
233
|
+
missing_components = []
|
|
234
|
+
required_components = %w(year month day hour minute)
|
|
235
|
+
required_components.each_with_index do |component, i|
|
|
236
|
+
missing_components << component unless date_data[i]
|
|
237
|
+
end
|
|
238
|
+
if missing_components.empty?
|
|
239
|
+
nil
|
|
240
|
+
else
|
|
241
|
+
params = [original_value.inspect, missing_components.join(", ")]
|
|
242
|
+
_("%s has missing components: %s") % params
|
|
243
|
+
end
|
|
244
|
+
else
|
|
245
|
+
_("%s is invalid time format") % original_value.inspect
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
class Integer < Base
|
|
251
|
+
SYNTAXES["1.3.6.1.4.1.1466.115.121.1.27"] = self
|
|
252
|
+
|
|
253
|
+
def type_cast(value)
|
|
254
|
+
return value if value.nil?
|
|
255
|
+
begin
|
|
256
|
+
Integer(value)
|
|
257
|
+
rescue ArgumentError
|
|
258
|
+
value
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def normalize_value(value)
|
|
263
|
+
if value.is_a?(::Integer)
|
|
264
|
+
value.to_s
|
|
265
|
+
else
|
|
266
|
+
value
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
private
|
|
271
|
+
def validate_normalized_value(value, original_value)
|
|
272
|
+
Integer(value)
|
|
273
|
+
nil
|
|
274
|
+
rescue ArgumentError
|
|
275
|
+
_("%s is invalid integer format") % original_value.inspect
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
class JPEG < Base
|
|
280
|
+
SYNTAXES["1.3.6.1.4.1.1466.115.121.1.28"] = self
|
|
281
|
+
|
|
282
|
+
private
|
|
283
|
+
def validate_normalized_value(value, original_value)
|
|
284
|
+
if value.unpack("n")[0] == 0xffd8
|
|
285
|
+
nil
|
|
286
|
+
else
|
|
287
|
+
_("invalid JPEG format")
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
class NameAndOptionalUID < Base
|
|
293
|
+
SYNTAXES["1.3.6.1.4.1.1466.115.121.1.34"] = self
|
|
294
|
+
|
|
295
|
+
private
|
|
296
|
+
def validate_normalized_value(value, original_value)
|
|
297
|
+
separator_index = value.rindex("#")
|
|
298
|
+
if separator_index
|
|
299
|
+
dn = value[0, separator_index]
|
|
300
|
+
bit_string = value[(separator_index + 1)..-1]
|
|
301
|
+
bit_string_reason = BitString.new.validate(bit_string)
|
|
302
|
+
dn_reason = DistinguishedName.new.validate(dn)
|
|
303
|
+
if bit_string_reason
|
|
304
|
+
if dn_reason
|
|
305
|
+
value_reason = DistinguishedName.new.validate(value)
|
|
306
|
+
return nil unless value_reason
|
|
307
|
+
dn_reason
|
|
308
|
+
else
|
|
309
|
+
bit_string_reason
|
|
310
|
+
end
|
|
311
|
+
else
|
|
312
|
+
dn_reason
|
|
313
|
+
end
|
|
314
|
+
else
|
|
315
|
+
DistinguishedName.new.validate(value)
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
class NumericString < Base
|
|
321
|
+
SYNTAXES["1.3.6.1.4.1.1466.115.121.1.36"] = self
|
|
322
|
+
|
|
323
|
+
private
|
|
324
|
+
def validate_normalized_value(value, original_value)
|
|
325
|
+
if /\A\d+\z/ =~ value
|
|
326
|
+
nil
|
|
327
|
+
else
|
|
328
|
+
_("%s is invalid numeric format") % original_value.inspect
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
class OID < Base
|
|
334
|
+
SYNTAXES["1.3.6.1.4.1.1466.115.121.1.38"] = self
|
|
335
|
+
|
|
336
|
+
private
|
|
337
|
+
def validate_normalized_value(value, original_value)
|
|
338
|
+
DN.parse("#{value}=dummy")
|
|
339
|
+
nil
|
|
340
|
+
rescue DistinguishedNameInvalid
|
|
341
|
+
reason = $!.reason
|
|
342
|
+
if reason
|
|
343
|
+
_("%s is invalid OID format: %s") % [original_value.inspect, reason]
|
|
344
|
+
else
|
|
345
|
+
_("%s is invalid OID format") % original_value.inspect
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
class OtherMailbox < Base
|
|
351
|
+
SYNTAXES["1.3.6.1.4.1.1466.115.121.1.39"] = self
|
|
352
|
+
|
|
353
|
+
private
|
|
354
|
+
def validate_normalized_value(value, original_value)
|
|
355
|
+
type, mailbox = value.split('$', 2)
|
|
356
|
+
|
|
357
|
+
if type.empty?
|
|
358
|
+
return _("%s has no mailbox type") % original_value.inspect
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
if /(#{UNPRINTABLE_CHARACTER})/i =~ type
|
|
362
|
+
format = _("%s has unprintable character in mailbox type: '%s'")
|
|
363
|
+
return format % [original_value.inspect, $1]
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
if mailbox.blank?
|
|
367
|
+
return _("%s has no mailbox") % original_value.inspect
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
nil
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
class PostalAddress < Base
|
|
375
|
+
SYNTAXES["1.3.6.1.4.1.1466.115.121.1.41"] = self
|
|
376
|
+
|
|
377
|
+
private
|
|
378
|
+
def validate_normalized_value(value, original_value)
|
|
379
|
+
if value.blank?
|
|
380
|
+
return _("empty string")
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
begin
|
|
384
|
+
value.unpack("U*")
|
|
385
|
+
rescue ArgumentError
|
|
386
|
+
return _("%s has invalid UTF-8 character") % original_value.inspect
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
nil
|
|
390
|
+
end
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
class PrintableString < Base
|
|
394
|
+
SYNTAXES["1.3.6.1.4.1.1466.115.121.1.44"] = self
|
|
395
|
+
|
|
396
|
+
private
|
|
397
|
+
def validate_normalized_value(value, original_value)
|
|
398
|
+
if value.blank?
|
|
399
|
+
return _("empty string")
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
if /(#{UNPRINTABLE_CHARACTER})/i =~ value
|
|
403
|
+
format = _("%s has unprintable character: '%s'")
|
|
404
|
+
return format % [original_value.inspect, $1]
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
nil
|
|
408
|
+
end
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
class TelephoneNumber < PrintableString
|
|
412
|
+
SYNTAXES["1.3.6.1.4.1.1466.115.121.1.50"] = self
|
|
413
|
+
|
|
414
|
+
private
|
|
415
|
+
def validate_normalized_value(value, original_value)
|
|
416
|
+
return nil if value.blank?
|
|
417
|
+
super
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
end
|
|
422
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require 'timeout'
|
|
2
|
+
|
|
3
|
+
module Timeout
|
|
4
|
+
|
|
5
|
+
# A forking timeout implementation that relies on
|
|
6
|
+
# signals to interrupt blocking I/O instead of passing
|
|
7
|
+
# that code to run in a separate process.
|
|
8
|
+
#
|
|
9
|
+
# A process is fork()ed, sleeps for _sec_,
|
|
10
|
+
# then sends a ALRM signal to the Process.ppid
|
|
11
|
+
# process. ALRM is used to avoid conflicts with sleep()
|
|
12
|
+
#
|
|
13
|
+
# This overwrites any signal
|
|
14
|
+
def Timeout.alarm(sec, exception=Timeout::Error, &block)
|
|
15
|
+
return block.call if sec == nil or sec.zero?
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# Trap an alarm in case it comes before we're ready
|
|
19
|
+
orig_alrm = trap(:ALRM, 'IGNORE')
|
|
20
|
+
|
|
21
|
+
# Setup a fallback in case of a race condition of an
|
|
22
|
+
# alarm before we set the other trap
|
|
23
|
+
trap(:ALRM) do
|
|
24
|
+
# Don't leave zombies
|
|
25
|
+
Process.wait2()
|
|
26
|
+
# Restore the original handler
|
|
27
|
+
trap('ALRM', orig_alrm)
|
|
28
|
+
# Now raise an exception!
|
|
29
|
+
raise exception, 'execution expired'
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Spawn the sleeper
|
|
33
|
+
pid = Process.fork {
|
|
34
|
+
begin
|
|
35
|
+
# Sleep x seconds then send SIGALRM
|
|
36
|
+
sleep(sec)
|
|
37
|
+
# Send alarm!
|
|
38
|
+
Process.kill(:ALRM, Process.ppid)
|
|
39
|
+
end
|
|
40
|
+
exit! 0
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
# Setup the real handler
|
|
44
|
+
trap(:ALRM) do
|
|
45
|
+
# Make sure we clean up any zombies
|
|
46
|
+
Process.waitpid(pid)
|
|
47
|
+
# Restore the original handler
|
|
48
|
+
trap(:ALRM, orig_alrm)
|
|
49
|
+
# Now raise an exception!
|
|
50
|
+
raise exception, 'execution expired'
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
begin
|
|
54
|
+
# Run the code!
|
|
55
|
+
return block.call
|
|
56
|
+
ensure
|
|
57
|
+
# Restore old alarm handler since we're done
|
|
58
|
+
trap(:ALRM, orig_alrm)
|
|
59
|
+
# Make sure the process is dead
|
|
60
|
+
# This may be run twice (trap occurs during execution) so ignore ESRCH
|
|
61
|
+
Process.kill(:TERM, pid) rescue Errno::ESRCH
|
|
62
|
+
# Don't leave zombies
|
|
63
|
+
Process.waitpid(pid) rescue Errno::ECHILD
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end # Timeout
|
|
67
|
+
|
|
68
|
+
if __FILE__ == $0
|
|
69
|
+
require 'time'
|
|
70
|
+
Timeout.alarm(2) do
|
|
71
|
+
loop do
|
|
72
|
+
p Time.now
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|