1 # -*- mode: perl; coding: utf-8 -*-
2 # Keitairc::SessionManager
3 # $Id: SessionManager.pm,v 1.9 2008-08-02 15:45:05 morimoto Exp $
4 # $Source: /home/ishikawa/work/keitairc/tmp/keitairc/lib/Keitairc/SessionManager.pm,v $
6 # Copyright (c) 2008 Jun Morimoto <morimoto@mrmt.net>
7 # This program is covered by the GNU General Public License 2
9 package Keitairc::SessionManager;
13 ################################################################
14 # my $sm = new Keitairc::SessionManager;
16 # my $sm = new Keitairc::SessionManager({default_ttl => 120});
23 $me->{default_ttl} = $arg->{default_ttl} || 60 * 30;
27 ################################################################
28 # $sm->verify({session_id => $session_id, user_agent => $user_agent});
29 # $sm->verify({serial_key => $serial_key, user_agent => $user_agent});
33 my $user_agent = $me->normalize_user_agent($arg->{user_agent});
36 # Keitairc::Log::log_debug("sm->verify: sid [$arg->{session_id}] serial_key [$arg->{serial_key}] user_agent [$arg->{user_agent}]");
38 if(defined $arg->{serial_key}){
39 if($s = $me->search_by_serial_key($arg->{serial_key}, $user_agent)){
40 # アクセスに合致する有効なセッションが見つかったら
42 return $me->refresh($s->{id}, $user_agent);
46 if(defined $arg->{session_id}){
47 if($s = $me->search_by_session_id($arg->{session_id}, $user_agent)){
48 # アクセスに合致する有効なセッションが見つかったら
50 return $me->refresh($s->{id}, $user_agent);
57 ################################################################
58 # 指定のセッションID文字列のセッションがあるか調べ、
60 # $sm->search_by_session_id($session_id, $user_agent);
61 sub search_by_session_id{
63 my $session_id = shift;
64 my $user_agent = shift;
66 $user_agent = $me->normalize_user_agent($user_agent);
67 if(my $s = $me->{sessions}->{$session_id}){
68 if($s->{user_agent} eq $user_agent){
69 if($s->{last_access_time} + $s->{ttl} >= time){
76 ################################################################
77 # 指定のセッションID文字列のセッションがあるか調べ、
79 # $sm->search_by_serial_key($serial_key, $user_agent);
80 sub search_by_serial_key{
82 my $serial_key = shift;
83 my $user_agent = shift;
85 $user_agent = $me->normalize_user_agent($user_agent);
87 for my $id (keys(%{$me->{sessions}})){
88 next unless defined $me->{sessions}->{$id}->{serial_key};
89 if($me->{sessions}->{$id}->{serial_key} eq $serial_key){
90 if($me->{sessions}->{$id}->{user_agent} eq $user_agent){
91 return $me->{sessions}->{$id};
97 ################################################################
98 # 指定のセッションID文字列のセッションの最終時刻を更新し、
100 # $sm->refresh($session_id, $user_agent);
103 my $session_id = shift;
104 my $user_agent = shift;
106 $user_agent = $me->normalize_user_agent($user_agent);
108 # good time to gc, huh?
109 $me->garbage_collect();
111 if(my $s = $me->{sessions}->{$session_id}){
112 if($s->{user_agent} eq $user_agent){
113 $s->{last_access_time} = time;
119 ################################################################
120 # 新たなセッションを始め、セッションオブジェクトを返す
121 # 認証が成功した直後など、有意なとき以外にやってはいけない
122 # $sm->add($user_agent, [$serial_key]);
125 my $user_agent = shift;
126 my $serial_key = shift;
128 return unless length $user_agent;
130 $user_agent = $me->normalize_user_agent($user_agent);
132 my @id_chars = ('a'..'z', 'A'..'Z');
137 $session_id .= $id_chars[rand(@id_chars)];
139 }while(defined $me->{sessions}->{$session_id});
141 my $s = $me->{sessions}->{$session_id} = {};
142 $s->{id} = $session_id;
143 $s->{ttl} = $me->{default_ttl};
144 $s->{user_agent} = $user_agent;
145 if(defined $serial_key){
146 $s->{serial_key} = $serial_key;
148 $s->{serial_key} = undef;
150 $s->{last_access_time} = time;
151 Keitairc::Log::log_debug(
152 dh('new session', $s,
153 qw(id user_agent last_access_time serial_key ttl)));
157 ################################################################
165 if(defined $obj->{$arg}){
166 push @buf, sprintf('%s[%s]', $arg, $obj->{$arg});
170 $title . ': ' . join(', ', @buf);
173 ################################################################
175 # $sm->garbage_collect();
178 for my $id (keys(%{$me->{sessions}})){
179 if(($me->{sessions}->{$id}->{last_access_time} +
180 $me->{sessions}->{$id}->{ttl}) < time){
181 delete $me->{sessions}->{$id};
182 Keitairc::Log::log_debug("deleted session: id[$id]");
187 ################################################################
190 my $session_id = shift;
191 delete $me->{sessions}->{$session_id};
194 ################################################################
195 # USER_AGENT文字列から、セッション判定の妨げとなる要素を取る
196 sub normalize_user_agent{
198 my $user_agent = shift;
200 # Keitairc::Log::log_debug("normalize_user_agent: user_agent[$user_agent]");
202 # NTT DoCoMoのFOMA端末製造番号 (15桁のユニークな英数字) および
203 # FOMAカード製造番号 (20桁のユニークな英数字) を除去
204 # http://www.nttdocomo.co.jp/service/imode/make/content/html/tag/utn.html
205 # DoCoMo/2.0 P703imyu(c100;TB;W30H15)
206 # DoCoMo/2.0 P703imyu(c100;TB;W30H15;ser123451234512345;icc12345678901234567890)
207 if($user_agent =~ m|^DoCoMo/|){
208 $user_agent =~ s/;ser[0-9a-zA-Z]{15}//;
209 $user_agent =~ s/;icc[0-9a-zA-Z]{20}//;
212 # SoftBank/Vodafone/J-PHONE
213 # http://developers.softbankmobile.co.jp/dp/tool_dl/web/useragent.php
214 if($user_agent =~ m!^(SoftBank|Vodafone|J-PHONE|MOT-)/!){
215 $user_agent =~ s|/SN[0-9A-Z]+|/|;
218 # Keitairc::Log::log_debug("normalize_user_agent: user_agent[$user_agent]");