1 package VJournal::Session;
9 use vars qw($AUTOLOAD);
10 use constant COOKIE_NAME=>'VJ_SESSION';
11 use constant CONFIG_NAME=>'.vjournalrc';
18 VJournal::Session - handle authorized use session
23 my $s = VJournal::Session->new;
27 B<VJournal::Session> manages session. Sesssion objects incoroprates
28 B<CGI.pm> context, and any methods of CGI.pm can be called as session
35 $session = new VJournal::Session();
36 $session = new VJournal::Session($cgi);
38 Creates new B<session> object based on the CGI request. If no CGI
39 object is expilcitely provided, creates one using default constructor.
41 If there is no session cookie in the CGI context, or cookie is expired,
42 or cookie is bound to IP address, other than current B<remote_addr()>,
51 %attrs=(-cgi=>new CGI);
52 } elsif (scalar(@_)%2==0) {
54 } elsif (scalar(@_) == 1) {
57 croak "Invalid call to VJournal::Session::new"
59 if (exists $attrs{-cgi} && $attrs{-cgi}->can("cookie")) {
61 my $sess_id = $cgi->cookie(COOKIE_NAME);
62 return undef unless $sess_id;
64 if (!exists($config{-sessionbase})) {
65 croak "No VJournal config read";
68 dbmopen %userbase,$config{-sessionbase},0644;
70 return undef if (!exists($userbase{$sess_id}));
71 my ($name,$identity,$avatar,$email,$avwidth,$avheight,$ip,$expire) =
72 split(/:/,$userbase{$sess_id});
73 if ($ip && $ip ne $attrs{-cgi}->remote_addr()) {
76 my $me={-id=>$sess_id,-name=>$name,-identity=>$identity,-cgi=>$cgi};
78 $me->{-avatar}=$avatar;
79 $me->{-avwidth}=$avwidth;
80 $me->{-avheight}=$avheight;
88 delete $userbase{$sess_id};
90 } elsif ($expire < $now - $config{-gracetime}) {
91 $expire+=$config{-sessiontime};
92 $userbase{$sess_id}=join(":",$name,$identity,$avatar,$email,$avwidth,$avheight,$ip,$expire);
94 [$cgi->cookie(-name=>COOKIE_NAME,-value=>$sess_id,-expires=>
97 return bless $me,$pkg;
103 Creates new session for given user. It is assumet that user have been
104 properly authenticated by caller. (i.e. using OpenID).
106 $session=VJournal::Session->create(-identity=>'identity-url',
107 -name=>"user display name",-cgi=>$cgi,-email=>$mailaddress,
112 If B<-bind_to_ip> is specified, session would be bound to IP address.
113 Avatar uri and email address might be provided by the authentication
116 If they are not obtained for free, caller shouldn't attempt to provide
117 them to create. Better to check if avatar and email are defined after
118 session creation. May be they are already cached.
124 if (scalar(@_)%2!=0) {
125 croak("Invalid call to ".$pkg."->create");
128 croack("User identity is required by ".$pkg."->create") unless
130 $params{-cgi}=CGI->new() if(!$params{-cgi});
131 load_config($params{-cgi});
132 my $identity=$params{-identity};
135 dbmopen %users,$config{-userbase},0644;
136 my $session={-cgi=>$params{-cgi},-identity=>$params{-identity}};
137 if (!exists($users{$identity})) {
139 require VJournal::Avatar;
141 if (exists $params{-avatar}) {
142 @avatar = VJournal::Avatar::cache($params{-avatar});
144 @avatar = VJournal::Avatar::by_openid($user);
146 if (!@avatar && exists $params{-email}) {
147 @avatar = VJournal::Avatar::by_email($params{-email});
150 $users{$identity}=join(":",$params{-name}||$identity
151 ,$params{-email},$a{-src},$a{-width},$a{-height});
153 my ($name,$email,$avatarsrc,$avatarwidth,$avatarheight)=split(":",$users{$user});
154 $session->{-name} = $name;
155 $session->{-email} = $email if $email;
157 $session->{-avatar} = $avatarsrc;
158 $session->{-avwidth} = $avatarwidth;
159 $session->{-avheight} = $avatarheight;
161 my $expire = time()+$config{-sessiontime};
164 $sessioninfo=join(":",$name,$identity,$avatarsrc,$email,$avatarwidth,$avatarheight,
165 ($params{-bind_to_ip}?$session->{-cgi}->remote_addr():""),$expire);
166 $session->{-id} = Digest::MD5::md5_base64($sessioninfo);
167 $sessions{$session->{-id}} = $sessioninfo;
170 [$session->cookie(-name=>COOKIE_NAME,-value=>$session->{-id},-expires=>
177 $s->set_cookie($s->cookie(-name=>name,-value=>value));
179 Stores new cookie to be send to client inside the session object.
180 They would be output when $s->header would be printed.
186 $self->{-cookie}=[] if !exists $self->{-cookie};
187 push @{$self->{-cookie}},@_;
194 Returns OpenID identity URL for current user
199 return shift->{-identity};
206 Returns display name for current user
211 return shift->{-name};
218 $s->avatar("http://www.some.site/userpic/user.gif");
220 In the scalar context returns img tag for user avatar.
221 In the vector context returns list which looks like
223 -src=>http://some.site/some.pic, -width=>nnn,-height=>nnn,-alt=>username
225 If URL is supplied, attempts to cache image in the local userpic area
226 so subsequent calls to the avatar would return local copy.
234 require VJournal::Avatar;
235 my %a = VJournal::Avatar::cache($_[0]);
236 while (my($key,$val)=each %a) {
239 $self->_update_user();
240 } elsif (exists($self->{-avatar})) {
241 my @a=(-src=>$self->{-avatar},-width=>$self->{-avwidth},-height=>$self->{-avheight},-alt=>$self->{-name});
245 return $self->{-cgi}->img(@a);
252 my $addr=$s->email();
261 $self->{-email} = shift;
262 if (!exists $self->{-avatar}) {
263 require VJournal::Avatar;
264 VJournal::Avatar::by_email($self->{-email});
266 $self->_update_user();
268 return $self->{-email};
276 returns true, if current user is owner of the blog
282 return $self->{-identity} eq $config->{-owner};
289 Return true if current user is banned from leaving comments in the blog.
294 return exists shift->{-ban}
299 $s->ban($identity_url);
301 Marks user as banned in the current blog
306 my ($self,$foe) = @_;
307 if (!$self->isowner()) return undef;
309 dbmopen %bans,$config{-topdir}."/bans",0644;
315 $session=>{-identity=>$identity,...,_readban($identity)}
317 Returns aray (-ban => 1) if $identity is recorded in tbe bans dbm file
323 my $identity = shift;
324 dbmopen %bans,$config{-topdir}."/bans",0644;
325 if (exists $bans{-identity}) {
336 Updates intformation about user in the user and session database.
337 Internal function, called from B<create>, B<avatar> and B<email>.
343 Overrideds CGI.pm header routine and adds to the header Set-Cookie
344 headers for cookies created by B<new>, B<create> or added by B<set_cookie>
350 push @_,-cookie=>$self->{-cookie} if exists($self->{-cookie}) ;
351 return $self->{-cgi}->header(@_);
358 walks up the path_translated() and searches for the B<.vjournalrc> config.
359 dies if config not found.
365 my $path=$cgi->path_translated();
366 my @dirs = File::Spec->splitdir($path);
367 my @uri = File::Spec->splitdir($cgi->path_info);
370 my $d=File::Spec->catdir(@dirs,CONFIG_NAME);
376 eval "%config = {$d}";
377 $config{-topdir}=File::Spec->catdir(@dirs);
378 $config{-topurl}=$cgi->url(-base=>1).File::Spec->catdir(@uri);
385 die ("Cannot find config file inside $path") unless $found;
386 my @reqkeys=qw(-statedir);
387 foreach my $key (@reqkeys) {
388 die "Required key $key missing from config"
389 unless exists $config{$key};
392 $config{-sessionbase}||=$config{-statedir}."/sessions.db";
393 $config{-userbase}||=$config{-statedir}."/user.db";
394 $config{-sessiontime}||=86400*30;
395 $config{-gracetime}||=86400;
396 $config{-templatedir}||=$config{-topdir}."/templates"
397 $config{-avatardir}||=$config{-topdir}."/avatars";
398 if (!$config{-owner}) {
399 my $uri=substr($config{-topurl},index($config{-topurl},"://")+2;
400 $uri =~ s/:\d+(\/.*)?$//;
401 $config{-owner} = $uri;
407 Delegates all called methods which are not implemented to the CGI.pm
415 my $func = $AUTOLOAD;;
416 croak("Invalid method $AUTOLOAD") unless CGI->can($func);
417 return $self->{-cgi}->$func(@_);