From: <de...@de...> - 2010-12-05 06:03:20
|
Author: CraigMeyer Date: 2010-12-05 00:03:08 -0600 (Sun, 05 Dec 2010) New Revision: 19920 Trac url: http://develop.twiki.org/trac/changeset/19920 Modified: twiki/trunk/EncryptPlugin/data/TWiki/EncryptPlugin.txt twiki/trunk/EncryptPlugin/lib/TWiki/Plugins/EncryptPlugin.pm twiki/trunk/EncryptPlugin/lib/TWiki/Plugins/EncryptPlugin/DEPENDENCIES twiki/trunk/EncryptPlugin/lib/TWiki/Plugins/EncryptPlugin/MANIFEST twiki/trunk/EncryptPlugin/lib/TWiki/Plugins/EncryptPlugin/build.pl Log: Item6617: Update EncryptPlugin - Almost complete, need to fix topic page Modified: twiki/trunk/EncryptPlugin/data/TWiki/EncryptPlugin.txt =================================================================== --- twiki/trunk/EncryptPlugin/data/TWiki/EncryptPlugin.txt 2010-12-05 02:11:15 UTC (rev 19919) +++ twiki/trunk/EncryptPlugin/data/TWiki/EncryptPlugin.txt 2010-12-05 06:03:08 UTC (rev 19920) @@ -1,5 +1,5 @@ -%META:TOPICINFO{author="TWikiContributor" date="1284795163" format="1.1" version="$Rev$"}% ----+!! Encrypt Plugin +%META:TOPICINFO{author="CraigMeyer" date="1291526668" format="1.1" reprev="1.4" version="1.4"}% +---+!! Encrypt Plugin (WORK IN PROGRESS) <!-- Contributions to this plugin are appreciated. Please update the plugin page at http://twiki.org/cgi-bin/view/Plugins/EncryptPlugin or provide feedback at @@ -9,9 +9,11 @@ * Set SHORTDESCRIPTION = Securely encrypt text in TWiki topics to be accessible by selected users only --> <sticky> -<div style="float:right; background-color:#EBEEF0; margin:0 0 20px 20px; padding: 0 10px 0 10px;"> +<div style="float:right; margin:0 0 10px 10px"> +<div style="background-color:#eeeeee; padding: 0 10px 0 10px"> %TOC{title="Page contents"}% </div> +</div> </sticky> %SHORTDESCRIPTION% @@ -47,6 +49,11 @@ =%<nop>ENCRYPT{"Jimmy Neutron"}%= encrypts text ="Jimmy Neutron"= to be viewable/editable only by the user who added the ENCRYPT variable. + 1. %ENCRYPT{_dont_change="DcoCU7Q8mB+M0P9LHCfULwxUTlMK7zwRcFQ3URdWg/w"}% + 1. %ENCRYPT{_dont_change="dBEVUsm8SVElzzXZzBkvuCTWuTk5opcVlKH/+IVu2Mc"}% + 1. %ENCRYPT{_dont_change="cJGOYU+3cUm4VDwL9tvtLTthJ1V+GQGlkrOyFNkqGbE"}% + + *2. Encrypt text for my group* =%<nop>ENCRYPT{"Helpdesk password: h3lp-Cu$t" allow="SupportGroup"}%= encrypts text to be viewable/editable by !SupportGroup members only. @@ -55,34 +62,14 @@ Other people see =<nop>*****<nop>= when looking at the page, and =%<nop>ENCRYPT{_dont_change="PPq2ez7j"}%= when editing the page. A non-member could change the ENCRYPT parameter the wiki way, which would invalidate the encrypted text. If this happens, anyone can view and restore the original text from a previous topic version, thus it is possible restore the encrypted text. ----++ Installation Instructions - -__Note:__ You do not need to install anything on the browser to use this plugin. The following instructions are for the administrator who installs the plugin on the TWiki server. - - * Download the ZIP file from the Plugin Home (see below) - * Unzip ==%TOPIC%.zip== in your twiki installation directory. Content: - | *File:* | *Description:* | - | ==data/TWiki/%TOPIC%.txt== | Plugin topic | - | ==data/TWiki/VarENCRYPT.txt== | Variable documentation | - | ==lib/TWiki/Plugins/%TOPIC%.pm== | Plugin Perl module | - * Create your asymetric key with openssl (currently only RSA key is supported): %BR% - =openssl genrsa -out /var/www/twiki/lib/cryptkey.priv 2048= - * Install the CPAN Dependencies listed in the Plugin Info section below - * Configure the Plugin: - * The TWiki =lib= directory is the default location of the private key file =cryptkey.priv=. If you store it in a different place add this setting to =twiki/lib/LocalSite.cfg=: %BR% - =$TWiki::cfg{Plugins}{EncryptPlugin}{PrivateKey} = '/path/to/cryptkey.priv';= - * Run the [[%SCRIPTURL{configure}%][configure]] script to enable the Plugin - * Test if the installation was successful: - * Add =%<nop>ENCRYPT{"any text"}%= to a topic in the Sandbox.WebHome web and verify that the text is viewable by you, and hidden by others. - ---++ Plugin Info -| Plugin Author: | TWiki:Main.PeterThoeny | +| Plugin Author: | TWiki:Main.PeterThoeny, [[http://twiki.net/][Twiki, Inc.]] | | Copyright: | © 2010, TWiki:Main.PeterThoeny %BR% © 2010, TWiki:TWiki.TWikiContributor | | License: | GPL ([[http://www.gnu.org/copyleft/gpl.html][GNU General Public License]]) | | Plugin Version: | %$VERSION% | | Change History: | <!-- versions below in reverse order --> | -| 2010-09-18: | TWikibug:Item6617: Initial version | +| 2010-11-15: | Initial version | | TWiki Dependency: | $TWiki::Plugins::VERSION 1.1 | | CPAN Dependencies: | CPAN:Mime::Base64, CPAN:Crypt::CBC, CPAN:Crypt::Rijndael_PP, CPAN:Crypt::RC4, CPAN:Crypt::OpenSSL::RSA | | Other Dependencies: | openssl to generate the asymetric key | @@ -93,3 +80,9 @@ | Appraisal: | http://TWiki.org/cgi-bin/view/Plugins/%TOPIC%Appraisal | __Related Topics:__ VarENCRYPT, %SYSTEMWEB%.TWikiPlugins, %SYSTEMWEB%.DeveloperDocumentationCategory, %SYSTEMWEB%.AdminDocumentationCategory, %SYSTEMWEB%.TWikiPreferences + +-- Main.PeterThoeny - 2010-11-15 + +%META:ENCRYPTPLUGIN{name="DcoCU7Q8mB+M0P9LHCfULwxUTlMK7zwRcFQ3URdWg/w" allow="SmallGroup" display="%25RED%25You can't see this! %25ENDCOLOR%25" index="0" value="U2FsdGVkX18UiqhEdPJvKlkUSVKWnLlBbS03AfH55/67pa94rw0caIcs4rNRc7g2z0bayxjo/T4=%0a"}% +%META:ENCRYPTPLUGIN{name="dBEVUsm8SVElzzXZzBkvuCTWuTk5opcVlKH/+IVu2Mc" allow="SmallGroup" display="%25RED%25You can't see this! %25ENDCOLOR%25" index="1" value="U2FsdGVkX1/y1lktK109xGAlVWRtzc29cWp4tvP5chyToijdaRREmu5O5SbXXr0w8laeHdRLTDw=%0a"}% +%META:ENCRYPTPLUGIN{name="cJGOYU+3cUm4VDwL9tvtLTthJ1V+GQGlkrOyFNkqGbE" allow="SmallGroup" display="%25RED%25You can't see this! %25ENDCOLOR%25" index="2" value="U2FsdGVkX18nGg3HJ1M3SomaqkcgrRSzwBQxDLGzqnDDCGWjoei7d7n9eVEQHEilPw99/yVP8I4=%0a"}% Modified: twiki/trunk/EncryptPlugin/lib/TWiki/Plugins/EncryptPlugin/DEPENDENCIES =================================================================== --- twiki/trunk/EncryptPlugin/lib/TWiki/Plugins/EncryptPlugin/DEPENDENCIES 2010-12-05 02:11:15 UTC (rev 19919) +++ twiki/trunk/EncryptPlugin/lib/TWiki/Plugins/EncryptPlugin/DEPENDENCIES 2010-12-05 06:03:08 UTC (rev 19920) @@ -0,0 +1,9 @@ +# Dependencies for EncryptPlugin +# Example: +# TWiki::Plugins,>=1.15,perl,TWiki 4.1 release. +# Crypt::OpenSSL::RSA,>=0.25,cpan,Required +# Crypt::CBC,>=2.30,cpan,Required +# Crypt::Blowfish,>=2.10,cpan,Required +# Crypt::RC4,>=2.02,cpan,Required +# MIME::Base64,>=3.13,cpan,Required +# Digest::MD6,>=0.11,cpan,Required Modified: twiki/trunk/EncryptPlugin/lib/TWiki/Plugins/EncryptPlugin/MANIFEST =================================================================== --- twiki/trunk/EncryptPlugin/lib/TWiki/Plugins/EncryptPlugin/MANIFEST 2010-12-05 02:11:15 UTC (rev 19919) +++ twiki/trunk/EncryptPlugin/lib/TWiki/Plugins/EncryptPlugin/MANIFEST 2010-12-05 06:03:08 UTC (rev 19920) @@ -1,3 +1,4 @@ -data/TWiki/EncryptPlugin.txt 0644 -data/TWiki/VarENCRYPT.txt 0664 -lib/TWiki/Plugins/EncryptPlugin.pm 0444 +# Release manifest for EncryptPlugin +data/TWiki/EncryptPlugin.txt 0644 Documentation +lib/TWiki/Plugins/EncryptPlugin.pm 0644 Perl module + Modified: twiki/trunk/EncryptPlugin/lib/TWiki/Plugins/EncryptPlugin/build.pl =================================================================== --- twiki/trunk/EncryptPlugin/lib/TWiki/Plugins/EncryptPlugin/build.pl 2010-12-05 02:11:15 UTC (rev 19919) +++ twiki/trunk/EncryptPlugin/lib/TWiki/Plugins/EncryptPlugin/build.pl 2010-12-05 06:03:08 UTC (rev 19920) @@ -1,18 +1,29 @@ #!/usr/bin/perl -w -# -# Build for EncryptPlugin -# BEGIN { - foreach my $pc (split(/:/, $ENV{TWIKI_LIBS})) { - unshift @INC, $pc; - } + unshift @INC, split( /:/, $ENV{TWIKI_LIBS} ); } - use TWiki::Contrib::Build; # Create the build object -$build = new TWiki::Contrib::Build( 'EncryptPlugin' ); +$build = new TWiki::Contrib::Build('EncryptPlugin'); +# (Optional) Set the details of the repository for uploads. +# This can be any web on any accessible TWiki installation. +# These defaults will be used when expanding tokens in .txt +# files, but be warned, they can be overridden at upload time! + +# name of web to upload to +$build->{UPLOADTARGETWEB} = 'Plugins'; + +# Full URL of pub directory +$build->{UPLOADTARGETPUB} = 'http://twiki.org/p/pub'; + +# Full URL of bin directory +$build->{UPLOADTARGETSCRIPT} = 'http://twiki.org/cgi-bin'; + +# Script extension +$build->{UPLOADTARGETSUFFIX} = ''; + # Build the target on the command line, or the default target -$build->build($build->{target}); +$build->build( $build->{target} ); Modified: twiki/trunk/EncryptPlugin/lib/TWiki/Plugins/EncryptPlugin.pm =================================================================== --- twiki/trunk/EncryptPlugin/lib/TWiki/Plugins/EncryptPlugin.pm 2010-12-05 02:11:15 UTC (rev 19919) +++ twiki/trunk/EncryptPlugin/lib/TWiki/Plugins/EncryptPlugin.pm 2010-12-05 06:03:08 UTC (rev 19920) @@ -1,9 +1,9 @@ # Plugin for TWiki Enterprise Collaboration Platform, http://TWiki.org/ # -# Copyright (C) 2010 Peter Thoeny, pe...@th... -# Copyright (C) 2010 TWiki Contributors -# All Rights Reserved. TWiki Contributors are listed in the -# AUTHORS file in the root of this distribution. +# Copyright (C) 2000-2003 Andrea Sterbini, a.s...@fl... +# Copyright (C) 2001-2010 Peter Thoeny, pe...@th... +# and TWiki Contributors. All Rights Reserved. TWiki Contributors +# are listed in the AUTHORS file in the root of this distribution. # NOTE: Please extend that file, not this notice. # # This program is free software; you can redistribute it and/or @@ -22,24 +22,119 @@ ---+ package EncryptPlugin +This is an empty TWiki plugin. It is a fully defined plugin, but is +disabled by default in a TWiki installation. Use it as a template +for your own plugins; see TWiki.TWikiPlugins for details. + +This version of the !EncryptPlugin documents the handlers supported +by revision 1.2 of the Plugins API. See the documentation of =TWiki::Func= +for more information about what this revision number means, and how a +plugin can check it. + +__NOTE:__ To interact with TWiki use ONLY the official API functions +in the TWiki::Func module. Do not reference any functions or +variables elsewhere in TWiki, as these are subject to change +without prior warning, and your plugin may suddenly stop +working. + +For increased performance, all handlers except initPlugin are +disabled below. *To enable a handler* remove the leading DISABLE_ from +the function name. For efficiency and clarity, you should comment out or +delete the whole of handlers you don't use before you release your +plugin. + +__NOTE:__ When developing a plugin it is important to remember that +TWiki is tolerant of plugins that do not compile. In this case, +the failure will be silent but the plugin will not be available. +See %TWIKIWEB%.TWikiPlugins#FAILEDPLUGINS for error messages. + +__NOTE:__ Defining deprecated handlers will cause the handlers to be +listed in %TWIKIWEB%.TWikiPlugins#FAILEDPLUGINS. See +%TWIKIWEB%.TWikiPlugins#Handlig_deprecated_functions +for information on regarding deprecated handlers that are defined for +compatibility with older TWiki versions. + +__NOTE:__ When writing handlers, keep in mind that these may be invoked +on included topics. For example, if a plugin generates links to the current +topic, these need to be generated before the afterCommonTagsHandler is run, +as at that point in the rendering loop we have lost the information that we +the text had been included from another topic. + =cut +# change the package name and $pluginName!!! package TWiki::Plugins::EncryptPlugin; # Always use strict to enforce variable scoping use strict; -require TWiki::Func; # The plugins API -require TWiki::Plugins; # For the API version +require TWiki::Func; # The plugins API +require TWiki::Plugins; # For the API version -use vars qw( $VERSION $RELEASE $SHORTDESCRIPTION $installWeb $debug $privateKey $pluginName $NO_PREFS_IN_TOPIC ); +# $VERSION is referred to by TWiki, and is the only global variable that +# *must* exist in this package. +use vars + qw( $VERSION $RELEASE $SHORTDESCRIPTION $debug $pluginName $NO_PREFS_IN_TOPIC ); -$VERSION = '$Rev$'; -$RELEASE = '2010-09-18'; +use vars qw( + $RSA_KEY_LEN + $RSA_PRIVATE_KEY_FILE + $RSA_PUBLIC_KEY_FILE + $RSA_KEY_FILE + $MY_SECRET_KEY + $MY_META_TYPE + $Method + %LOOKUP_FUNCS +); -$SHORTDESCRIPTION = 'Securely encrypt text in TWiki topics to be accessible by selected users only'; -$NO_PREFS_IN_TOPIC = 0; +use Data::Dumper; +use FileHandle; +use Crypt::CBC; +use Crypt::OpenSSL::RSA; +use Crypt::Blowfish; +use Crypt::RC4; +use MIME::Base64; +use TWiki::Attrs; +use Digest::MD6; +$RSA_KEY_LEN = 2048; +$RSA_KEY_FILE = "/var/www/tw/lib/TWiki/Plugins/cryptkey.both"; +$RSA_PRIVATE_KEY_FILE = "/var/www/tw/lib/TWiki/Plugins/cryptkey.priv"; +$RSA_PUBLIC_KEY_FILE = "/var/www/tw/lib/TWiki/Plugins/cryptkey.pub"; + +$MY_SECRET_KEY = 'This is my secret key'; +$MY_META_TYPE = 'ENCRYPTPLUGIN'; + +%LOOKUP_FUNCS = ( + 'BLOWFISH' => 'Blowfish', + 'RSA_RC4' => 'Crypt::RC4', +); + +# This should always be $Rev: 18620 (2010-10-10) $ so that TWiki can determine the checked-in +# status of the plugin. It is used by the build automation tools, so +# you should leave it alone. +$VERSION = '$Rev: 18620 (2010-10-10) $'; + +# This is a free-form string you can use to "name" your own plugin version. +# It is *not* used by the build automation tools, but is reported as part +# of the version number in PLUGINDESCRIPTIONS. Add your own release number +# such as '1.3' or release date such as '2010-05-08' +$RELEASE = '0.1'; + +# Short description of this plugin +# One line description, is shown in the %TWIKIWEB%.TextFormattingRules topic: +$SHORTDESCRIPTION = +'Securely encrypt text in TWiki topics to be accessible by selected users only.'; + +# You must set $NO_PREFS_IN_TOPIC to 0 if you want your plugin to use preferences +# stored in the plugin topic. This default is required for compatibility with +# older plugins, but imposes a significant performance penalty, and +# is not recommended. Instead, use $TWiki::cfg entries set in LocalSite.cfg, or +# if you want the users to be able to change settings, then use standard TWiki +# preferences that can be defined in your Main.TWikiPreferences and overridden +# at the web and topic level. +$NO_PREFS_IN_TOPIC = 1; + # Name of this Plugin, only used in this module $pluginName = 'EncryptPlugin'; @@ -51,179 +146,531 @@ * =$user= - the login name of the user * =$installWeb= - the name of the web the plugin is installed in +REQUIRED + +Called to initialise the plugin. If everything is OK, should return +a non-zero value. On non-fatal failure, should write a message +using TWiki::Func::writeWarning and return 0. In this case +%FAILEDPLUGINS% will indicate which plugins failed. + +In the case of a catastrophic failure that will prevent the whole +installation from working safely, this handler may use 'die', which +will be trapped and reported in the browser. + +You may also call =TWiki::Func::registerTagHandler= here to register +a function to handle variables that have standard TWiki syntax - for example, +=%MYTAG{"my param" myarg="My Arg"}%. You can also override internal +TWiki variable handling functions this way, though this practice is unsupported +and highly dangerous! + +__Note:__ Please align variables names with the Plugin name, e.g. if +your Plugin is called FooBarPlugin, name variables FOOBAR and/or +FOOBARSOMETHING. This avoids namespace issues. + + =cut +sub errMsg { + TWiki::Func::writeDebug( join( ' ', "$pluginName: ", @_ ) ); +} # errMsg + +sub dbgMsg { + if ($debug) { + + # print STDERR join( ' ', @msgs ), "\n"; + TWiki::Func::writeDebug( join( ' ', "$pluginName: ", @_ ) ); + } +} # dbgMsg + +sub checkModule ($) { + my ($module) = @_; + + eval("require $module;"); + if ($@) { + return (1); + } + return (0); +} # checkModule + sub initPlugin { - my( $topic, $web, $user, $installWeb ) = @_; + my ( $topic, $web, $user, $installWeb ) = @_; # check for Plugins.pm versions - if( $TWiki::Plugins::VERSION < 1.1 ) { - TWiki::Func::writeWarning( "Version mismatch between $pluginName and Plugins.pm" ); + if ( $TWiki::Plugins::VERSION < 1.026 ) { + TWiki::Func::writeWarning( + "Version mismatch between $pluginName and Plugins.pm"); return 0; } - # Get plugin settings - $debug = $TWiki::cfg{Plugins}{EncryptPlugin}{Debug} || 0; - $privateKey = $TWiki::cfg{Plugins}{EncryptPlugin}{PrivateKey} - || 'cryptkey.priv'; + if ( !-f $RSA_KEY_FILE ) { + my ( $rsa_gen, $hout ); + $rsa_gen = Crypt::OpenSSL::RSA->generate_key($RSA_KEY_LEN); + + $hout = new FileHandle(">$RSA_KEY_FILE"); + if ($hout) { + print $hout $rsa_gen->get_private_key_string(); + print $hout $rsa_gen->get_public_key_string(); + $hout->close(); + } + else { + TWiki::Func::writeWarning( + "Can't write RSA_KEY_FILE in $pluginName"); + return (0); + } + } + + # + # Check if needed CPAN modules are around + # + my ( $module, $errors ); + $errors = 0; + foreach $module ( + ( + 'Crypt::CBC', 'Crypt::OpenSSL::RSA', + 'Crypt::RC4', 'MIME::Base64', + 'Digest::MD6' + ) + ) + { + if ( checkModule($module) ) { + TWiki::Func::writeWarning("Missing Support Module [$module]"); + $errors++; + } + } + if ( $errors > 0 ) { + return (0); + } + + # Set plugin preferences in LocalSite.cfg, like this: + # $TWiki::cfg{Plugins}{EncryptPlugin}{ExampleSetting} = 1; + # Always provide a default in case the setting is not defined in + # LocalSite.cfg. See TWiki.TWikiPlugins for help in adding your plugin + # configuration to the =configure= interface. + # my $setting = $TWiki::cfg{Plugins}{EncryptPlugin}{ExampleSetting} || 0; + + $debug = $TWiki::cfg{Plugins}{EncryptPlugin}{Debug} || 0; + $debug = 1; + $Method = uc( $TWiki::cfg{Plugins}{EncryptPlugin}{Default_Method} ) + || 'BLOWFISH'; + if ( !exists( $LOOKUP_FUNCS{$Method} ) ) { + dbgMsg("*** No such Default_Method [$Method], switching to BLOWFISH"); + $Method = 'BLOWFISH'; + } + + # register the _ENCRYPT function to handle %ENCRYPT{...}% + TWiki::Func::registerTagHandler( 'ENCRYPT', \&_ENCRYPT ); + # Plugin correctly initialized return 1; -} +} # initPlugin -=pod +sub readRSAKey ($$) { + my ( $fname, $mode ) = @_; + my ( $hin, $both_keys ); ----++ commonTagsHandler() + $hin = new FileHandle("<$fname"); + if ($hin) { + local ($/); + $/ = undef; + $both_keys = <$hin>; + $hin->close(); + } + else { + die "Can't open [$fname]\n"; + } -This handles the %ENCRYPT{...}% variable in view + if ( uc($mode) eq 'PUBLIC' ) { + $both_keys =~ s/^.*?--+END RSA PRIVATE KEY--+[\r\n]+//s; + } + elsif ( uc($mode) eq 'PRIVATE' ) { + $both_keys =~ s/[\r\n]+--+BEGIN RSA PUBLIC KEY.*$//s; + } + else { + return ($both_keys); + } -=cut + # dbgMsg("readRSAKey: [$mode] [$both_keys]"); + return ($both_keys); +} # readRSAKey -sub commonTagsHandler { - # do not uncomment, use $_[0], $_[1]... instead - ### my ( $text, $topic, $web, $inInclude, $meta ) = @_; +sub encrypt ($$) { + my ( $method, $text ) = @_; + my ( $cipher, $tmp ); -#use Data::Dumper; -#print STDERR "===(START===)\n" . Dumper($_[4]) . "\n====(END)===="; + $cipher = Crypt::CBC->new( + -key => $MY_SECRET_KEY, + -cipher => $LOOKUP_FUNCS{$method}, + ); - TWiki::Func::writeDebug( "- ${pluginName}::commonTagsHandler( $_[2].$_[1] )" ) if $debug; - $_[0] =~ s/%ENCRYPT\{(.*?)\}%/_handleEncryptOnView( $1, $_[4] )/geo; -} + #didn't work! + # $tmp = Crypt::RSA->new(readRSAKey($RSA_KEY_FILE, 'BOTH')); + # $cipher = Crypt::CBC->new( -cipher => $tmp ); -=pod + $text = $cipher->encrypt($text); + return ( MIME::Base64::encode($text) ); +} # encrypt ----++ beforeEditHandler($text, $topic, $web ) +sub decrypt ($$) { + my ( $method, $base64_text ) = @_; + my ( $text, $cipher, $tmp ); -=cut + $text = MIME::Base64::decode($base64_text); -sub beforeEditHandler { - # do not uncomment, use $_[0], $_[1]... instead - ### my ( $text, $topic, $web ) = @_; + $cipher = Crypt::CBC->new( + -key => $MY_SECRET_KEY, + -cipher => $LOOKUP_FUNCS{$method}, + ); - TWiki::Func::writeDebug( "- ${pluginName}::beforeEditHandler( $_[2].$_[1] )" ) if $debug; + #didn't work! + # $tmp = Crypt::RSA->new(readRSAKey($RSA_KEY_FILE, 'BOTH')); + # $cipher = Crypt::CBC->new( -cipher => $tmp ); + return ( $cipher->decrypt($text) ); - return unless( $_[0] =~ /%ENCRYPT{/ ); +} # decrypt -# # FIXME: Hack to extract %META:ENCRYPTPLUGIN meta data from text with embedded meta data -# # (proper solution is to enhance the plugins API with session and meta data) -# my $metaEncrypt; -#print STDERR "start loop\n"; -# foreach my $line ( split( /[\r\n]+/, $_[0] ) ) { -#print STDERR "testing line: $line\n"; -# # Example: %META:ENCRYPTPLUGIN{name="y7t6C6MJ" allow="..." value="..."}% -# if( $line =~ /^%META:ENCRYPTPLUGIN\{ *name=\"([^\"]*)\" *allow=\"([^\"]*)\" *value=\"([^\"]*)\" *\}%/ ) { -# if( $line =~ /^%META:ENCRYPTPLUGIN\{(.*?)\}%/ ) { -#print STDERR "found $1 (allow $2, value $3)\n"; -# $metaEncrypt->{$1} = { -# allow => TWiki::Store::dataDecode( $2 ), -# value => TWiki::Store::dataDecode( $3 ), -# }; -# } -# } -#print STDERR "end loop\n"; +#sub encryptRSA { +# my ($text) = @_; +# my ($rsa_public); +# +# dbgMsg("encryptRSA"); +# +# $rsa_public = Crypt::OpenSSL::RSA->new_public_key( +# readRSAKey( $RSA_KEY_FILE, 'PUBLIC' ) ); +# +# # $rsa_public->use_sslv23_padding(); +# # $rsa_public->use_pkcs1_padding(); +# $text = $rsa_public->encrypt($text); +# return ( MIME::Base64::encode($text) ); +#} # encryptRSA +# +#sub decryptRSA ($) { +# my ($base64_text) = @_; +# my ( $text, $rsa_private ); +# +# dbgMsg("decryptRSA"); +# +# $text = MIME::Base64::decode($base64_text); +# $rsa_private = Crypt::OpenSSL::RSA->new_private_key( +# readRSAKey( $RSA_KEY_FILE, 'PRIVATE' ) ); +# +# # $rsa_private->use_sslv23_padding(); +# # $rsa_private->use_pkcs1_padding(); +# +# return ( $rsa_private->decrypt($text) ); +#} # decryptRSA +# - $_[0] =~ s/%ENCRYPT\{(.*?)\}%/_handleEncryptOnEdit( $1, $_[3] )/geo; -} +sub sign_text ($) { + my ($text) = @_; + my ($rsa_private); -=pod + $rsa_private = Crypt::OpenSSL::RSA->new_private_key( + readRSAKey( $RSA_KEY_FILE, 'PRIVATE' ) ); ----++ beforeSaveHandler($text, $topic, $web, $meta ) - * =$text= - text _with embedded meta-data tags_ - * =$topic= - the name of the topic in the current CGI query - * =$web= - the name of the web in the current CGI query - * =$meta= - the metadata of the topic being saved, represented by a TWiki::Meta object. + return ( MIME::Base64::encode( $rsa_private->sign($text) ) ); +} # sign_text -=cut +sub verify_signature ($$) { + my ( $text, $signature ) = @_; + my ($rsa_private); -sub beforeSaveHandler { - # do not uncomment, use $_[0], $_[1]... instead - ### my ( $text, $topic, $web ) = @_; + $rsa_private = Crypt::OpenSSL::RSA->new_private_key( + readRSAKey( $RSA_KEY_FILE, 'PRIVATE' ) ); - $_[0] =~ s/%ENCRYPT\{(.*?)\}%/_handleEncryptOnSave( $1, $_[3] )/geo; + return ( $rsa_private->verify( $text, MIME::Base64::decode($signature) ) ); +} # verify_signature - TWiki::Func::writeDebug( "- ${pluginName}::beforeSaveHandler( $_[2].$_[1] )" ) if $debug; -} +sub hash_string ($) { + my ($text) = @_; -=pod + return ( Digest::MD6::md6_base64($text) ); +} # hash_string ----++ _handleEncryptOnView() +sub _inList ($$) { + my ( $user, $allowed_str ) = @_; + my ( @list, $name ); -=cut + @list = split( /\s*,\s*/, $allowed_str ); + foreach $name (@list) { + $name =~ s/(Main\.|\%MAINWEB\%\.)//go; # strip leading web. + if ( + $name eq $user + || ( TWiki::Func::isGroup($name) + && TWiki::Func::isGroupMember( $name, $user ) ) + ) + { + dbgMsg("inList: Found [$user] in [$name]"); + return (1); + } + } -sub _handleEncryptOnView -{ - my ( $params, $meta ) = @_; + return (0); +} #_inList - my $text = '<nop>*****<nop>'; - my $attrs = new TWiki::Attrs( $params ); - if( $attrs->{_dont_change} ) { - my $metaEncrypt = $meta->get( 'ENCRYPTPLUGIN', $attrs->{_dont_change} ); - if( $metaEncrypt ) { - my $allow = $metaEncrypt->{allow}; - if( - $allow eq TWiki::Func::getWikiName() || - $allow eq TWiki::Func::getCanonicalUserID() || - TWiki::Func::isGroupMember( $allow ) - ) { - $text = "Found: $metaEncrypt->{name}, allow: $metaEncrypt->{allow}, value: $metaEncrypt->{value}"; +# CRAIG +# The function used to handle the %ENCRYPT{...}% variable +# Check if $meta is working +# + +my ($encrypt_index); + +sub _ENCRYPT { + my ( $session, $params, $theTopic, $theWeb, $meta ) = @_; + + # $session - a reference to the TWiki session object (if you don't know + # what this is, just ignore it) + # $params= - a reference to a TWiki::Attrs object containing parameters. + # This can be used as a simple hash that maps parameter names + # to values, with _DEFAULT being the name for the default + # parameter. + # $theTopic - name of the topic in the query + # $theWeb - name of the web in the query + # Return: the result of processing the variable + + my ( $tmp, $key_id, $user ); + + $key_id = $params->{'_dont_change'} || undef; + $user = TWiki::Func::getWikiName(); + + dbgMsg("View ENCRYPT: [$user] [$key_id]"); + dbgMsg( "Raw: [", $params->{_RAW}, "]" ); + dbgMsg( "Meta: [", $meta->stringify($MY_META_TYPE), "]" ); + + if ( defined($key_id) ) { + my ( $pinfo, $pattrs, $cipher_text, $allow_list, $display, + $clear_text ); + $pinfo = $meta->get( $MY_META_TYPE, $key_id ); + $cipher_text = $pinfo->{value} || ''; + $allow_list = $pinfo->{allow} || ''; + $display = $pinfo->{display} || '******'; + + if ( $cipher_text ne '' ) { + if ( _inList( $user, $allow_list ) ) { + $clear_text = decrypt( $Method, $cipher_text ); + dbgMsg("Result [$clear_text]"); + return ($clear_text); } + else { + dbgMsg("Result [$display]"); + return ($display); + } } + else { + $tmp = join( '', '%<nop>ENCRYPT{', $params->{_RAW}, '}%' ); + errMsg("No Cipher result [$tmp]"); + return ($tmp); + } } - return $text; -} -=pod + return ("%RED% Unexpected Finish %ENDCOLOR%"); +} # _ENCRYPT ----++ _handleEncryptOnEdit() +sub _handleBeforeEdit { + my ( $arg_string, $web, $topic, $pmeta ) = @_; + my ( $params, $error, $key_id, $user, $result ); -=cut + $params = TWiki::Attrs->new($arg_string); + $user = TWiki::Func::getWikiName(); + $key_id = $params->{'_dont_change'} || undef; -sub _handleEncryptOnEdit -{ - my ( $params, $meta ) = @_; + $error = 0; - my $attrs = new TWiki::Attrs( $params ); + dbgMsg("_handleBeforeEdit: [$key_id] [$encrypt_index]"); - my $text = "<nop>*** edit **<nop> {$params} - " . $meta->get( 'ENCRYPTPLUGIN', $attrs->{_dont_change} )->{value}; - return $text; -} + if ( defined($key_id) ) { + my ( $pinfo, $cipher_text, $clear_text, $allow_list, $display ); + $pinfo = $pmeta->get( $MY_META_TYPE, $key_id ); + dbgMsg( "Meta: [", $pmeta->stringify($MY_META_TYPE), "]" ); + $cipher_text = $pinfo->{value} || ''; + + if ( defined($cipher_text) && $cipher_text ne '' ) { + $allow_list = $pinfo->{allow}; + + if ( _inList( $user, $allow_list ) ) { + $clear_text = decrypt( $Method, $cipher_text ); + $display = $pinfo->{display}; + $result = join( ' ', + '"' . $clear_text . '"', + 'allow="' . $allow_list . '"', + 'display="' . $display . '"' ); + + # remove Meta data before edit + $pmeta->remove( $MY_META_TYPE, $key_id ); + } + else { + $result = $arg_string; + } + } + else { + $result = $arg_string; + } + } + else { + $error++; + $result = $arg_string; + } + + $result = join( '', '%ENCRYPT{', $result, '}%' ); + if ( $error > 0 ) { + $result = join( ' ', "%RED%", $result, "%ENDCOLOR%" ); + } + + dbgMsg("Done $encrypt_index: [$result]"); + dbgMsg( "Meta: [", $pmeta->stringify($MY_META_TYPE), "]" ); + + $encrypt_index++; + + return ($result); +} # _handleBeforeEdit + +# +# Called by beforeSaveHandler() +# + +sub _handleBeforeSave { + my ( $arg_string, $web, $topic, $pmeta ) = @_; + my ( + $params, $error, $clear_text, $allow_list, + $display, $key_id, $cipher_text, $signature, + $hash, $user, $result + ); + + $params = TWiki::Attrs->new($arg_string); + $user = TWiki::Func::getWikiName(); + + $clear_text = $params->{_DEFAULT} || undef; + $allow_list = $params->{allow} || $user; + $display = $params->{display} || '******'; + $key_id = $params->{'_dont_change'} || undef; + + $error = 0; + + dbgMsg( +"_handleBeforeSave: [$clear_text] [$allow_list] [$display] [$key_id] [$encrypt_index]" + ); + + if ( defined($clear_text) && $clear_text ne '' ) { + $cipher_text = encrypt( $Method, $clear_text ); + $signature = sign_text( $allow_list . $clear_text . $encrypt_index ); + $hash = hash_string($signature); + $pmeta->putKeyed( + $MY_META_TYPE, + { + name => $hash, + allow => $allow_list, + value => $cipher_text, + display => $display, + index => "$encrypt_index" + } + ); + $result = "_dont_change=\"$hash\""; + } + elsif ( defined($key_id) ) { + my ($pinfo); + $pinfo = $pmeta->get( $MY_META_TYPE, $key_id ); + $cipher_text = $pinfo->{value} || ''; + $hash = ''; + if ( defined($cipher_text) && $cipher_text ne '' ) { + $clear_text = decrypt( $Method, $cipher_text ); + $allow_list = $pinfo->{allow}; + $signature = + sign_text( $allow_list . $clear_text . $pinfo->{index} ); + $hash = hash_string($signature); + } + if ( $hash ne $key_id ) { + $error = 1; + errMsg("*** Something was modified [$arg_string]!"); + } + $result = "_dont_change=\"$key_id\""; + } + + $result = join( '', '%ENCRYPT{', $result, '}%' ); + if ( $error > 0 ) { + $result = join( ' ', "%RED%", $result, "%ENDCOLOR%" ); + } + + dbgMsg("Done $encrypt_index: [$result]"); + dbgMsg( "Meta: ", $pmeta->stringify($MY_META_TYPE), "]" ); + + $encrypt_index++; + + return ($result); +} # _handleBeforeSave + =pod ----++ _handleEncryptOnSave() +---++ beforeEditHandler($text, $topic, $web ) + * =$text= - text that will be edited + * =$topic= - the name of the topic in the current CGI query + * =$web= - the name of the web in the current CGI query +This handler is called by the edit script just before presenting the edit text +in the edit box. It is called once when the =edit= script is run. +__NOTE__: meta-data may be embedded in the text passed to this handler +(using %META: tags) + +*Since:* TWiki::Plugins::VERSION = '1.010' + =cut -sub _handleEncryptOnSave -{ - my ( $params, $meta ) = @_; +sub beforeEditHandler { - my $attrs = new TWiki::Attrs( $params ); - my $rand = _randomStr(); + # do not uncomment, use $_[0], $_[1]... instead + ### my ( $text, $topic, $web ) = @_; - $meta->putKeyed( 'ENCRYPTPLUGIN', { name => $rand, allow => $attrs->{allow}, value => $attrs->{_DEFAULT} } ); + TWiki::Func::writeDebug("- ${pluginName}::beforeEditHandler( $_[2].$_[1] )") + if $debug; - my $text = '%ENCRYPT{'; -# $text .= '"' . $attrs->{_DEFAULT} . '"'; -# $text .= ' allow="' . $attrs->{allow} . '"'; - $text .= '_dont_change="' . $rand . '"}%'; - return $text; -} + # my ( $text, $topic, $web, $meta ); + # $text = $_[0]; + # $topic = $_[1]; + # $web = $_[2]; + # $meta = $_[3]; + $encrypt_index = 0; + $_[0] =~ s/%ENCRYPT{(.*?)}%/_handleBeforeEdit($1, $_[2], $_[1], $_[3])/sgeo; + +} # beforeEditHandler + =pod ----++ _randomStr() +---++ beforeSaveHandler($text, $topic, $web, $meta ) + * =$text= - text _with embedded meta-data tags_ + * =$topic= - the name of the topic in the current CGI query + * =$web= - the name of the web in the current CGI query + * =$meta= - the metadata of the topic being saved, represented by a TWiki::Meta object. +This handler is called each time a topic is saved. + +__NOTE:__ meta-data is embedded in =$text= (using %META: tags). If you modify +the =$meta= object, then it will override any changes to the meta-data +embedded in the text. Modify *either* the META in the text *or* the =$meta= +object, never both. You are recommended to modify the =$meta= object rather +than the text, as this approach is proof against changes in the embedded +text format. + +*Since:* TWiki::Plugins::VERSION = '1.010' + =cut -sub _randomStr -{ - my @chars=('a'..'z','A'..'Z','0'..'9'); - my $str = ''; - foreach ( 1..8 ) { - $str .= $chars[rand @chars]; - } - return $str; -} +sub beforeSaveHandler { + # do not uncomment, use $_[0], $_[1]... instead + ### my ( $text, $topic, $web ) = @_; + + TWiki::Func::writeDebug("- ${pluginName}::beforeSaveHandler( $_[2].$_[1] )") + if $debug; + + # my ( $text, $topic, $web, $meta ); + # $text = $_[0]; + # $topic = $_[1]; + # $web = $_[2]; + # $meta = $_[3]; + + $encrypt_index = 0; + $_[0] =~ s/%ENCRYPT{(.*?)}%/_handleBeforeSave($1, $_[2], $_[1], $_[3])/sgeo; +} # beforeSaveHandler + 1; |