From 40672ee7d6396b42bf2e2bd99a42210575a74c2d Mon Sep 17 00:00:00 2001 From: Alex Schroeder Date: Wed, 14 Nov 2012 17:35:52 +0100 Subject: [PATCH 1/6] No bullet point before div.refer a elements. --- css/alex-2012.css | 3 --- 1 file changed, 3 deletions(-) diff --git a/css/alex-2012.css b/css/alex-2012.css index 3d6fbb8d..264edae7 100644 --- a/css/alex-2012.css +++ b/css/alex-2012.css @@ -149,9 +149,6 @@ div.refer { line-height: 13pt; } -div.refer a:first-child:before { content: "" } -div.refer a:before { content: "• " } - div.message { background-color:#fee; color:#000; From 23484cce314e04d842a3435a725be6a9985f79e3 Mon Sep 17 00:00:00 2001 From: Alex Schroeder Date: Fri, 16 Nov 2012 15:51:19 +0100 Subject: [PATCH 2/6] Prevent double "Showing revision X" by passing QUIET to GetTextRevision. --- modules/namespaces.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/namespaces.pl b/modules/namespaces.pl index fbb9cfb5..2d75b0c8 100644 --- a/modules/namespaces.pl +++ b/modules/namespaces.pl @@ -376,7 +376,7 @@ sub NewNamespaceBrowsePage { #REDIRECT into different namespaces my ($id, $raw, $comment, $status) = @_; OpenPage($id); - my ($text, $revision) = GetTextRevision(GetParam('revision', '')); + my ($text, $revision) = GetTextRevision(GetParam('revision', ''), 1); my $oldId = GetParam('oldid', ''); if (not $oldId and not $revision and (substr($text, 0, 10) eq '#REDIRECT ') and (($WikiLinks and $text =~ /^\#REDIRECT\s+(($InterSitePattern:)?$InterLinkPattern)/) From 7da4732ce458db189d1d99bb822de3517df1d332 Mon Sep 17 00:00:00 2001 From: Alex Schroeder Date: Fri, 16 Nov 2012 15:51:56 +0100 Subject: [PATCH 3/6] Whitespace. --- wiki.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wiki.pl b/wiki.pl index aa8c4192..465b1b5f 100755 --- a/wiki.pl +++ b/wiki.pl @@ -2495,7 +2495,7 @@ sub PrintHtmlDiff { if ($type == 1) { $old = $Page{lastmajor} - 1; ($text, $new) = GetTextRevision($Page{lastmajor}, 1) - unless $new or $Page{lastmajor} == $Page{revision}; + unless $new or $Page{lastmajor} == $Page{revision}; } elsif ($new) { $old = $new - 1; } else { From 4f47511314802571ef919b8482b057047a795b34 Mon Sep 17 00:00:00 2001 From: Alex Schroeder Date: Fri, 16 Nov 2012 17:12:12 +0100 Subject: [PATCH 4/6] Private pages! --- modules/private-pages.pl | 111 +++++++++++++++++++++++++++++++++++++++ t/private-pages.t | 89 +++++++++++++++++++++++++++++++ 2 files changed, 200 insertions(+) create mode 100644 modules/private-pages.pl create mode 100644 t/private-pages.t diff --git a/modules/private-pages.pl b/modules/private-pages.pl new file mode 100644 index 00000000..6e8c90cf --- /dev/null +++ b/modules/private-pages.pl @@ -0,0 +1,111 @@ +# Copyright (C) 2012 Alex Schroeder +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +=head1 Private Pages Extension + +This module allows you to hide the content of particular pages in Oddmuse. +Unlike the I, this is not based on the user's role of +editor or administrator. Instead, every page can have a different password by +beginning it with #PASSWORD XYZZY where XYZZY is the password required to read +it. Multiple passwords can be supplied, separated by spaces. + +Note that all the meta information of the private page remains public: The +I of the page, the fact that is has been edited, the author, the +revision, the content of past revisions that have not been protected by a +password all remain visible to other users. + +Notes: + +=over + +=item * This extension might not work in a mod_perl environment because it + sets C<$NewText> without ever resetting it. + +=item * If you're protecting a comment page, people can still leave comments + -- they just can't read the resulting page. + +=back + +=cut + +$ModulesDescription .= '

private-pages.pl, see Private Pages Extension

'; + +sub PrivatePageLocked { + my $text = shift; + my ($line) = split(/\n/, $text, 1); + my @token = split(/\s+/, $line); + my $lock = 0; + if (shift(@token) eq '#PASSWORD') { + my $pwd = GetParam('pwd', ''); + $lock = 1; + foreach (@token) { + if ($pwd eq $_) { + $lock = 0; + break; + } + } + } + return $lock; +} + +*OldPrivatePagesUserCanEdit = *UserCanEdit; +*UserCanEdit = *NewPrivatePagesUserCanEdit; + +sub NewPrivatePagesUserCanEdit { + my ($id, $editing, @rest) = @_; + my $result = OldPrivatePagesUserCanEdit($id, $editing, @rest); + # GetPageContent bypasses OpenPage! + if ($result > 0 and $editing and PrivatePageLocked(GetPageContent($id))) { + return 0; + } else { + return $result; + } +} + +*OldPrivatePagesOpenPage = *OpenPage; +*OpenPage = *NewPrivatePagesOpenPage; + +sub NewPrivatePagesOpenPage { + OldPrivatePagesOpenPage(@_); + if (PrivatePageLocked($Page{text})) { + %Page = (); # reset everything + $NewText = Ts('This page is password protected. If you know the password, you can %s. Once you have done that, return and reload this page.', + '[' . ScriptUrl('action=password') . ' ' + . T('supply the password now') . ']'); + } + return $OpenPageName; +} + +push(@MyRules, \&PrivatePageRule); + +sub PrivatePageRule { + if (pos == 0 && m/\G#PASSWORD.*\n/gc) { + return ''; + } + return undef; +} + +*OldPrivatePagesGetSummary = *GetSummary; +*GetSummary = *NewPrivatePagesGetSummary; + +sub NewPrivatePagesGetSummary { + my $text = GetParam('text', ''); + if ($text and $text =~ /^#PASSWORD\b/ + # no text means aftertext is set (leaving a comment) + or $Page{text} =~ /^#PASSWORD\b/) { + # if no summary was set, set something in order to avoid the default + return ''; + } + return OldPrivatePagesGetSummary(); +} diff --git a/t/private-pages.t b/t/private-pages.t new file mode 100644 index 00000000..7eda9ef5 --- /dev/null +++ b/t/private-pages.t @@ -0,0 +1,89 @@ +# Copyright (C) 2012 Alex Schroeder +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +require 't/test.pl'; +package OddMuse; +use Test::More tests => 26; + +clear_pages(); +add_module('private-pages.pl'); + +# create password protected page: can't read it without password! +test_page(update_page('Privat', "#PASSWORD foo\nSo many secrets remain untold.\n"), + 'This page is password protected'); + +# can't update password protected page +update_page('Privat', "#PASSWORD foo\nCats have secrets.\n"); +test_page($redirect, 'Status: 403'); + +# use password foo to update protected page: can't read it without password! +test_page_negative(update_page('Privat', "#PASSWORD foo\nCats have secrets.\n", undef, undef, 1), + 'Cats have secrets'); +test_page($redirect, 'Status: 302'); + +# read it with password +my $page = get_page('action=browse id=Privat pwd=foo'); +test_page_negative($page, 'This page is password protected'); +test_page($page, 'Cats have secrets'); + +# a keep file was created as well +ok(-f GetKeepFile('Privat', 1), 'Keep file exists'); + +# can't read old revisions without a password +test_page_negative(get_page('action=browse id=Privat revision=1'), + 'Cats have secrets'); + +# read old revisions with password +test_page(get_page('action=browse id=Privat revision=1 pwd=foo'), + 'So many secrets remain untold'); + +# can't see secrets when printing raw pages +my $page = get_page('action=browse raw=1 id=Privat pwd=foo'); +test_page_negative($page, 'This page is password protected'); +test_page($page, 'Cats have secrets'); + +# can't see summaries with secrets +my $page = get_page('action=rc raw=1 all=1'); +test_page($page, 'Privat'); +test_page_negative($page, 'secret'); + +# can't search for secrets without a password +my $page = get_page('search=cats'); +test_page($page, '0 pages found'); +test_page_negative($page, "Privat"); + +# search finds secrets with password +my $page = get_page('search=cats pwd=foo'); +test_page($page, '1 pages? found', + 'Privat', 'Cats have secrets'); + +# can't edit a private page without a password +my $page = get_page('action=edit id=Privat'); +test_page($page, 'Editing not allowed'); +test_page_negative($page, 'Cats have secrets'); + +# can edit a private page with a password +my $page = get_page('action=edit id=Privat pwd=foo'); +test_page_negative($page, 'This page is password protected'); +test_page($page, 'Cats have secrets'); + +# can't edit an old revision of a private page without a password +my $page = get_page('action=edit id=Privat revision=1'); +test_page($page, 'Editing not allowed'); +test_page_negative($page, 'secret'); + +# can't just post changes to a private page without a password +my $page = get_page('title=Privat text=YaddaYadda revision=1'); +test_page($page, 'Editing not allowed'); +test_page_negative($page, 'secret'); From b73dc255bb2857aa7bfc0c00b3b3888862973410 Mon Sep 17 00:00:00 2001 From: Alex Schroeder Date: Fri, 16 Nov 2012 17:56:25 +0100 Subject: [PATCH 5/6] Fix docstring. --- modules/fix-encoding.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/fix-encoding.pl b/modules/fix-encoding.pl index be82d00a..28f2d932 100644 --- a/modules/fix-encoding.pl +++ b/modules/fix-encoding.pl @@ -13,7 +13,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -$ModulesDescription .= '

fix-encoding.pl

'; +$ModulesDescription .= '

fix-encoding.pl, see Fix Encoding

'; $Action{'fix-encoding'} = \&FixEncoding; From 6bac95b7ebe7dad016248fab0a641376d85d522f Mon Sep 17 00:00:00 2001 From: Alex Schroeder Date: Fri, 16 Nov 2012 18:38:27 +0100 Subject: [PATCH 6/6] Fix a loophole where using allowed you to see hidden pages. --- modules/private-pages.pl | 33 +++++++++++++++++++++++++-------- t/private-pages.t | 6 +++++- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/modules/private-pages.pl b/modules/private-pages.pl index 6e8c90cf..894b2c32 100644 --- a/modules/private-pages.pl +++ b/modules/private-pages.pl @@ -65,12 +65,20 @@ sub PrivatePageLocked { sub NewPrivatePagesUserCanEdit { my ($id, $editing, @rest) = @_; my $result = OldPrivatePagesUserCanEdit($id, $editing, @rest); - # GetPageContent bypasses OpenPage! - if ($result > 0 and $editing and PrivatePageLocked(GetPageContent($id))) { - return 0; - } else { - return $result; + # bypass OpenPage and GetPageContent (these are redefined below) + if ($result > 0 and $editing and $IndexHash{$id}) { + my %data = ParseData(ReadFileOrDie(GetPageFile($id))); + if (PrivatePageLocked($data{text})) { + return 0; + } } + return $result; +} + +sub PrivatePageMessage { + return Ts('This page is password protected. If you know the password, you can %s. Once you have done that, return and reload this page.', + '[' . ScriptUrl('action=password') . ' ' + . T('supply the password now') . ']'); } *OldPrivatePagesOpenPage = *OpenPage; @@ -80,13 +88,22 @@ sub NewPrivatePagesOpenPage { OldPrivatePagesOpenPage(@_); if (PrivatePageLocked($Page{text})) { %Page = (); # reset everything - $NewText = Ts('This page is password protected. If you know the password, you can %s. Once you have done that, return and reload this page.', - '[' . ScriptUrl('action=password') . ' ' - . T('supply the password now') . ']'); + $NewText = PrivatePageMessage(); } return $OpenPageName; } +*OldPrivatePagesGetPageContent = *GetPageContent; +*GetPageContent = *NewPrivatePagesGetPageContent; + +sub NewPrivatePagesGetPageContent { + my $text = OldPrivatePagesGetPageContent(@_); + if (PrivatePageLocked($text)) { + return PrivatePageMessage(); + } + return $text; +} + push(@MyRules, \&PrivatePageRule); sub PrivatePageRule { diff --git a/t/private-pages.t b/t/private-pages.t index 7eda9ef5..664b8aac 100644 --- a/t/private-pages.t +++ b/t/private-pages.t @@ -14,7 +14,7 @@ require 't/test.pl'; package OddMuse; -use Test::More tests => 26; +use Test::More tests => 27; clear_pages(); add_module('private-pages.pl'); @@ -87,3 +87,7 @@ test_page_negative($page, 'secret'); my $page = get_page('title=Privat text=YaddaYadda revision=1'); test_page($page, 'Editing not allowed'); test_page_negative($page, 'secret'); + +# can't include them +test_page_negative(update_page('Publik', ''), + 'Cats have secrets');