Description:
fix authen pop3 bugs and redundant code
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r406:b2fd7182e3dc - - 1 file changed: 2 inserted, 13 deleted

@@ -1,380 +1,369
1 1 require 'digest/sha1'
2 2 require 'net/pop'
3 + require 'net/https'
4 + require 'net/http'
3 5 require 'json'
4 6
5 7 class User < ActiveRecord::Base
6 8
7 9 has_and_belongs_to_many :roles
8 10
9 11 has_many :test_requests, :order => "submitted_at DESC"
10 12
11 13 has_many :messages,
12 14 :class_name => "Message",
13 15 :foreign_key => "sender_id",
14 16 :order => 'created_at DESC'
15 17
16 18 has_many :replied_messages,
17 19 :class_name => "Message",
18 20 :foreign_key => "receiver_id",
19 21 :order => 'created_at DESC'
20 22
21 23 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
22 24
23 25 belongs_to :site
24 26 belongs_to :country
25 27
26 28 has_and_belongs_to_many :contests, :uniq => true, :order => 'name'
27 29
28 30 scope :activated_users, :conditions => {:activated => true}
29 31
30 32 validates_presence_of :login
31 33 validates_uniqueness_of :login
32 34 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
33 35 validates_length_of :login, :within => 3..30
34 36
35 37 validates_presence_of :full_name
36 38 validates_length_of :full_name, :minimum => 1
37 39
38 40 validates_presence_of :password, :if => :password_required?
39 41 validates_length_of :password, :within => 4..20, :if => :password_required?
40 42 validates_confirmation_of :password, :if => :password_required?
41 43
42 44 validates_format_of :email,
43 45 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
44 46 :if => :email_validation?
45 47 validate :uniqueness_of_email_from_activated_users,
46 48 :if => :email_validation?
47 49 validate :enough_time_interval_between_same_email_registrations,
48 50 :if => :email_validation?
49 51
50 52 # these are for ytopc
51 53 # disable for now
52 54 #validates_presence_of :province
53 55
54 56 attr_accessor :password
55 57
56 58 before_save :encrypt_new_password
57 59 before_save :assign_default_site
58 60 before_save :assign_default_contest
59 61
60 62 # this is for will_paginate
61 63 cattr_reader :per_page
62 64 @@per_page = 50
63 65
64 66 def self.authenticate(login, password)
65 67 user = find_by_login(login)
66 68 if user
67 69 return user if user.authenticated?(password)
68 70 if user.authenticated_by_cucas?(password) or user.authenticated_by_pop3?(password)
69 71 user.password = password
70 72 user.save
71 73 return user
72 74 end
73 75 end
74 76 end
75 77
76 78 def authenticated?(password)
77 79 if self.activated
78 80 hashed_password == User.encrypt(password,self.salt)
79 81 else
80 82 false
81 83 end
82 84 end
83 85
84 86 def authenticated_by_pop3?(password)
85 87 Net::POP3.enable_ssl
86 88 pop = Net::POP3.new('pops.it.chula.ac.th')
87 89 authen = true
88 90 begin
89 - pop.start(login, password) # (1)
90 - pop.finish
91 - return true
92 - rescue
93 - return false
94 - end
95 - end
96 -
97 - def authenticated_by_pop3?(password)
98 - Net::POP3.enable_ssl
99 - pop = Net::POP3.new('pops.it.chula.ac.th')
100 - authen = true
101 - begin
102 91 pop.start(login, password)
103 92 pop.finish
104 93 return true
105 94 rescue
106 95 return false
107 96 end
108 97 end
109 98
110 99 def authenticated_by_cucas?(password)
111 100 url = URI.parse('https://www.cas.chula.ac.th/cas/api/?q=studentAuthenticate')
112 101 appid = '41508763e340d5858c00f8c1a0f5a2bb'
113 102 appsecret ='d9cbb5863091dbe186fded85722a1e31'
114 103 post_args = {
115 104 'appid' => appid,
116 105 'appsecret' => appsecret,
117 106 'username' => login,
118 107 'password' => password
119 108 }
120 109
121 110 #simple call
122 111 begin
123 112 resp = Net::HTTP.post_form(url, post_args)
124 113 result = JSON.parse resp.body
125 114 return true if result["type"] == "beanStudent"
126 115 rescue
127 116 return false
128 117 end
129 118 return false
130 119 end
131 120
132 121 def admin?
133 122 self.roles.detect {|r| r.name == 'admin' }
134 123 end
135 124
136 125 def email_for_editing
137 126 if self.email==nil
138 127 "(unknown)"
139 128 elsif self.email==''
140 129 "(blank)"
141 130 else
142 131 self.email
143 132 end
144 133 end
145 134
146 135 def email_for_editing=(e)
147 136 self.email=e
148 137 end
149 138
150 139 def alias_for_editing
151 140 if self.alias==nil
152 141 "(unknown)"
153 142 elsif self.alias==''
154 143 "(blank)"
155 144 else
156 145 self.alias
157 146 end
158 147 end
159 148
160 149 def alias_for_editing=(e)
161 150 self.alias=e
162 151 end
163 152
164 153 def activation_key
165 154 if self.hashed_password==nil
166 155 encrypt_new_password
167 156 end
168 157 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
169 158 end
170 159
171 160 def verify_activation_key(key)
172 161 key == activation_key
173 162 end
174 163
175 164 def self.random_password(length=5)
176 165 chars = 'abcdefghjkmnopqrstuvwxyz'
177 166 password = ''
178 167 length.times { password << chars[rand(chars.length - 1)] }
179 168 password
180 169 end
181 170
182 171 def self.find_non_admin_with_prefix(prefix='')
183 172 users = User.find(:all)
184 173 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
185 174 end
186 175
187 176 # Contest information
188 177
189 178 def self.find_users_with_no_contest()
190 179 users = User.find(:all)
191 180 return users.find_all { |u| u.contests.length == 0 }
192 181 end
193 182
194 183
195 184 def contest_time_left
196 185 if GraderConfiguration.contest_mode?
197 186 return nil if site==nil
198 187 return site.time_left
199 188 elsif GraderConfiguration.indv_contest_mode?
200 189 time_limit = GraderConfiguration.contest_time_limit
201 190 if time_limit == nil
202 191 return nil
203 192 end
204 193 if contest_stat==nil or contest_stat.started_at==nil
205 194 return (Time.now.gmtime + time_limit) - Time.now.gmtime
206 195 else
207 196 finish_time = contest_stat.started_at + time_limit
208 197 current_time = Time.now.gmtime
209 198 if current_time > finish_time
210 199 return 0
211 200 else
212 201 return finish_time - current_time
213 202 end
214 203 end
215 204 else
216 205 return nil
217 206 end
218 207 end
219 208
220 209 def contest_finished?
221 210 if GraderConfiguration.contest_mode?
222 211 return false if site==nil
223 212 return site.finished?
224 213 elsif GraderConfiguration.indv_contest_mode?
225 214 return false if self.contest_stat(true)==nil
226 215 return contest_time_left == 0
227 216 else
228 217 return false
229 218 end
230 219 end
231 220
232 221 def contest_started?
233 222 if GraderConfiguration.indv_contest_mode?
234 223 stat = self.contest_stat
235 224 return ((stat != nil) and (stat.started_at != nil))
236 225 elsif GraderConfiguration.contest_mode?
237 226 return true if site==nil
238 227 return site.started
239 228 else
240 229 return true
241 230 end
242 231 end
243 232
244 233 def update_start_time
245 234 stat = self.contest_stat
246 235 if stat == nil or stat.started_at == nil
247 236 stat ||= UserContestStat.new(:user => self)
248 237 stat.started_at = Time.now.gmtime
249 238 stat.save
250 239 end
251 240 end
252 241
253 242 def problem_in_user_contests?(problem)
254 243 problem_contests = problem.contests.all
255 244
256 245 if problem_contests.length == 0 # this is public contest
257 246 return true
258 247 end
259 248
260 249 contests.each do |contest|
261 250 if problem_contests.find {|c| c.id == contest.id }
262 251 return true
263 252 end
264 253 end
265 254 return false
266 255 end
267 256
268 257 def available_problems_group_by_contests
269 258 contest_problems = []
270 259 pin = {}
271 260 contests.enabled.each do |contest|
272 261 available_problems = contest.problems.available
273 262 contest_problems << {
274 263 :contest => contest,
275 264 :problems => available_problems
276 265 }
277 266 available_problems.each {|p| pin[p.id] = true}
278 267 end
279 268 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
280 269 contest_problems << {
281 270 :contest => nil,
282 271 :problems => other_avaiable_problems
283 272 }
284 273 return contest_problems
285 274 end
286 275
287 276 def available_problems
288 277 if not GraderConfiguration.multicontests?
289 278 return Problem.find_available_problems
290 279 else
291 280 contest_problems = []
292 281 pin = {}
293 282 contests.enabled.each do |contest|
294 283 contest.problems.available.each do |problem|
295 284 if not pin.has_key? problem.id
296 285 contest_problems << problem
297 286 end
298 287 pin[problem.id] = true
299 288 end
300 289 end
301 290 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
302 291 return contest_problems + other_avaiable_problems
303 292 end
304 293 end
305 294
306 295 def can_view_problem?(problem)
307 296 if not GraderConfiguration.multicontests?
308 297 return problem.available
309 298 else
310 299 return problem_in_user_contests? problem
311 300 end
312 301 end
313 302
314 303 protected
315 304 def encrypt_new_password
316 305 return if password.blank?
317 306 self.salt = (10+rand(90)).to_s
318 307 self.hashed_password = User.encrypt(self.password,self.salt)
319 308 end
320 309
321 310 def assign_default_site
322 311 # have to catch error when migrating (because self.site is not available).
323 312 begin
324 313 if self.site==nil
325 314 self.site = Site.find_by_name('default')
326 315 if self.site==nil
327 316 self.site = Site.find(1) # when 'default has be renamed'
328 317 end
329 318 end
330 319 rescue
331 320 end
332 321 end
333 322
334 323 def assign_default_contest
335 324 # have to catch error when migrating (because self.site is not available).
336 325 begin
337 326 if self.contests.length == 0
338 327 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
339 328 if default_contest
340 329 self.contests = [default_contest]
341 330 end
342 331 end
343 332 rescue
344 333 end
345 334 end
346 335
347 336 def password_required?
348 337 self.hashed_password.blank? || !self.password.blank?
349 338 end
350 339
351 340 def self.encrypt(string,salt)
352 341 Digest::SHA1.hexdigest(salt + string)
353 342 end
354 343
355 344 def uniqueness_of_email_from_activated_users
356 345 user = User.activated_users.find_by_email(self.email)
357 346 if user and (user.login != self.login)
358 347 self.errors.add_to_base("Email has already been taken")
359 348 end
360 349 end
361 350
362 351 def enough_time_interval_between_same_email_registrations
363 352 return if !self.new_record?
364 353 return if self.activated
365 354 open_user = User.find_by_email(self.email,
366 355 :order => 'created_at DESC')
367 356 if open_user and open_user.created_at and
368 357 (open_user.created_at > Time.now.gmtime - 5.minutes)
369 358 self.errors.add_to_base("There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
370 359 end
371 360 end
372 361
373 362 def email_validation?
374 363 begin
375 364 return VALIDATE_USER_EMAILS
376 365 rescue
377 366 return false
378 367 end
379 368 end
380 369 end
You need to be logged in to leave comments. Login now