logout.pl 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. #!/usr/bin/env perl
  2. use strict;
  3. use v5.10;
  4. # ====================[ logout.pl ]====================
  5. =head1 NAME
  6. logout - An Oddmuse module for logging out the current Oddmuse user.
  7. =head1 SYNOPSIS
  8. logout logs out the current Oddmuse user from the current Oddmuse Wiki by
  9. clearing that user's client-side, Oddmuse-specific HTML cookie. As this cookie
  10. persists that user's username and and (optional) password for this Oddmuse Wiki,
  11. clearing this cookie effectively logs that user off this Oddmuse Wiki.
  12. Viola!
  13. =head1 INSTALLATION
  14. logout is easily installable: move this file into the B<wiki/modules/>
  15. directory of your Oddmuse Wiki.
  16. =cut
  17. AddModuleDescription('logout.pl', 'Logout Extension');
  18. our ($q, %Action, $CommentsPrefix, $Message, $LinkPattern, $FreeLinks, $FreeLinkPattern, $SiteName, %CookieParameters);
  19. # ....................{ CONFIGURATION }....................
  20. =head1 CONFIGURATION
  21. logout is easily configurable: set these variables in the B<wiki/config.pl>
  22. file for your Oddmuse Wiki.
  23. =cut
  24. our ($CommentsSuffix,
  25. $LogoutIsDebugging);
  26. =head2 $CommentsSuffix
  27. A string that, unless blank, supplants that default
  28. "${CommentsPrefix}${PageName}" link (e.g., "Comment on Logout_Extension")
  29. in the edit bar with a new, page-agnostic
  30. "${CommentsPrefix}${CommentsSuffix}" link (e.g., "Comment on this page"). Since
  31. this string is blank, by default, it performs no such replacement. Enable it by
  32. setting the string to some non-blank value in your B<wiki/config.pl> file; e.g.,
  33. $CommentsSuffix = 'this page';
  34. If you do set this variable, please also ensure that you have set the
  35. C<$CommentsPrefix> variable. (If that variable is not set, but this variable is,
  36. this variable is rudely ignored. Such is life in the insensate code trenches!)
  37. This variable's intent is to lend some minute uniformity to the edit bar. All
  38. the edit bar's other links ("Edit this page," "View other revisions",
  39. "Administration," and so on) are page-agnostic; these links do not reference
  40. the current page's name. Why, then, should the comment link be any different?
  41. While an admittedly minor point, it is a point... This variable addresses it.
  42. Lastly. Although this variable has, clearly, little relation to the cookie-
  43. clearing implementation of the rest of this module, this module's author
  44. conspired no better place for it - and therefore placed it here. (Do with it
  45. what thou wilt, museful wrangler!)
  46. =cut
  47. #$CommentsSuffix = 'this page';
  48. $CommentsSuffix = '';
  49. =head2 $LogoutIsDebugging
  50. A boolean that, if true, prints all key-value pairs (composing the currently
  51. requested URL query and current user's cookie) with each Oddmuse Wiki page; and,
  52. if false, does nothing. This boolean defaults to false.
  53. Key-value pairs are printed by appending their contents onto Oddmuse's
  54. C<$Message> variable, which Oddmuse then tacks onto the header for each page.
  55. =cut
  56. $LogoutIsDebugging = '';
  57. # ....................{ ACTIONS }....................
  58. $Action{logout} = \&DoLogout;
  59. =head1 ACTIONS
  60. =head2 DoLogout
  61. Logs the current user "out."
  62. This erases every entry in that user's client-side, site-specific cookie, which
  63. has several unnerving effects:
  64. =over
  65. =item The user's currently cached username is discarded. As the username, in
  66. the Oddmuse security model, is an aesthetic artifice having no relation
  67. to whether that user is an editor, administrator, or merely 'visitor',
  68. this doesn't do very much.
  69. =item The user's currently cached password is discarded. If the user was logged
  70. in as editor or administrator, that user is now logged off and, hereafter,
  71. merely considered a 'visitor'.
  72. =item All other key-value pairs are discarded. (This might serve as a decent
  73. mechanism for testing cookie-specific functionality in your own module,
  74. elsewhere.)
  75. =back
  76. =cut
  77. sub DoLogout {
  78. my $id = shift;
  79. SetParam('username', $CookieParameters{username});
  80. SetParam('pwd', $CookieParameters{pwd});
  81. print
  82. GetHeader('', Ts('Logged out of %s', $SiteName), '') .
  83. $q->div({-class=> 'content'}, $q->p(T('You are now logged out.'), $id ? $q->p(ScriptLink('action=browse;id=' . UrlEncode($id) . '&time=' . time, Ts('Return to %s', NormalToFree($id)))) : ''));
  84. PrintFooter();
  85. }
  86. # ....................{ FUNCTIONS }....................
  87. *GetFooterLinksLogoutOld = \&GetFooterLinks;
  88. *GetFooterLinks = \&GetFooterLinksLogout;
  89. =head1 FUNCTIONS
  90. =head2 GetFooterLinksLogout
  91. Appends a "Logout" link onto the edit bar in the footer of each page.
  92. =cut
  93. sub GetFooterLinksLogout {
  94. my ($id, $rev) = @_;
  95. my $footer_links = GetFooterLinksLogoutOld(@_);
  96. if ($CommentsPrefix and $CommentsSuffix) {
  97. $footer_links =~ s
  98. /(\Q<a class="comment\E.+?>).+?(<\/a>)
  99. /$1.NormalToFree($CommentsPrefix.$CommentsSuffix).$2
  100. /ex;
  101. }
  102. # Display the link to the "Logout" action iff the current user's already logged
  103. # in with some username or password.
  104. if (GetParam('username', '') ne '' or
  105. GetParam('pwd', '') ne '') {
  106. my $action = 'action=logout';
  107. $action .= ';id=' . UrlEncode($id) if $id;
  108. $footer_links =~ s
  109. /(.+)(<\/.+?>)$
  110. /$1.' '.ScriptLink($action, T('Logout'), 'logout').$2
  111. /ex;
  112. } else {
  113. my $action = 'action=password';
  114. $action .= ';id=' . UrlEncode($id) if $id;
  115. $footer_links =~ s
  116. /(.+)(<\/.+?>)$
  117. /$1.' '.ScriptLink($action, T('Login'), 'login').$2
  118. /ex;
  119. }
  120. return $footer_links;
  121. }
  122. =head2 CookieUsernameFix
  123. Corrects the C<CookieUsernameFix> function, which, in its original definition,
  124. caused a festering heap of trouble.
  125. We suspect a flaw in the innate coding of that function. But, whatever the
  126. fickle case, it's supplanted here with a (somewhat) stabler version.
  127. =cut
  128. sub CookieUsernameFix {
  129. if ($LogoutIsDebugging) {
  130. $Message .= "<table>";
  131. $Message .= "<tr><td>QUERY::</td></tr>";
  132. my %query_parameters = $q->Vars;
  133. foreach my $query_parameter_name (keys %query_parameters) {
  134. $Message .= "<tr>"
  135. ."<td>${query_parameter_name}:</td>"
  136. ."<td>$query_parameters{$query_parameter_name}</td></tr>";
  137. }
  138. $Message .= "<tr><td>COOKIE::</td></tr>";
  139. my ($changed, %cookie_parameters) = CookieData();
  140. foreach my $cookie_parameter (keys %cookie_parameters) {
  141. $Message.="<tr>"
  142. ."<td>${cookie_parameter}:</td>"
  143. ."<td>$cookie_parameters{$cookie_parameter}</td></tr>";
  144. }
  145. $Message .= "</table>";
  146. }
  147. # Only valid usernames get stored in the new cookie.
  148. my $name = GetParam('username', '');
  149. if (!$name) { }
  150. elsif (!$FreeLinks && !($name =~ /^$LinkPattern$/)) {
  151. CookieUsernameFixDelete(Ts('Invalid UserName %s: not saved.', $name));
  152. }
  153. elsif ($FreeLinks && (!($name =~ /^$FreeLinkPattern$/))) {
  154. CookieUsernameFixDelete(Ts('Invalid UserName %s: not saved.', $name));
  155. }
  156. elsif (length($name) > 50) { # Too long
  157. CookieUsernameFixDelete(T('UserName must be 50 characters or less: not saved'));
  158. }
  159. }
  160. sub CookieUsernameDelete {
  161. if ($LogoutIsDebugging) {
  162. $Message .= $q->p(shift);
  163. }
  164. $q->delete('username');
  165. }
  166. =head1 INTERFACE
  167. logout considers an Oddmuse user to be logged in if and only if that user has
  168. entered either some username or one of two site-wide passwords. (See
  169. L<SECURITY>, below.)
  170. If the current Oddmuse Wiki user is logged in, this module appends a "Logout"
  171. link to the edit bar; if not, this module does not. (That, perchance, ill-named
  172. edit bar is the second line of navigational, administerial links in the footer
  173. for each page.)
  174. If the current Oddmuse Wiki user is logged in and does click on that "Logout"
  175. link in the edit bar, this module logs out that user by clearing the user's
  176. client-side, site-specific cookie of all key-value pair content.
  177. Oddmuse should, arguably, bundle this easy functionality into the main
  178. Oddmuse script. It doesn't; so, we do it here.
  179. =head1 SECURITY
  180. logout inherits its security model from Oddmuse, to which it makes no serious
  181. change. Now, Oddmuse has no pre-defined mechanism for managing users; rather,
  182. when editing any editable page or commenting on any commentable page, anyone
  183. may enter any username in the "Username:" edit field. That username need not
  184. be registered, approved, or otherwise managed (as in other content management
  185. systems). That username, as such, has no user-defined password, passphrase, or
  186. other identifying token. Any user may masquerade as any other user, with happy
  187. impunity!
  188. logout retains this (admittedly loose) concept of a "user."
  189. =head1 SEE ALSO
  190. logout is "little brother" to the login module - from which it was inspired and
  191. for which it's partly named, in antiparallel.
  192. logout only implements a slim subset of functionality implemented by the login
  193. module. For a full-bodied, fully configurable alternative to Oddmuse security,
  194. please use that module instead.
  195. =head1 COPYRIGHT AND LICENSE
  196. The information below applies to everything in this distribution,
  197. except where noted.
  198. Copyleft 2008 by B.w.Curry <http://www.raiazome.com>.
  199. This program is free software; you can redistribute it and/or modify
  200. it under the terms of the GNU General Public License as published by
  201. the Free Software Foundation; either version 3 of the License, or
  202. (at your option) any later version.
  203. This program is distributed in the hope that it will be useful,
  204. but WITHOUT ANY WARRANTY; without even the implied warranty of
  205. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  206. GNU General Public License for more details.
  207. You should have received a copy of the GNU General Public License
  208. along with this program. If not, see <http://www.gnu.org/licenses/>.
  209. =cut