From e73864fceaded2cd947add1713e9e8321e50d674 Mon Sep 17 00:00:00 2001 From: Matthew Connelly Date: Sat, 14 Nov 2015 04:39:28 +0000 Subject: [PATCH] a lot of changes, hoo boy. made the expiry check interval configurable (expire_every in config.yml) fixed a bug where an expired paste could still be viewed for a short period after expiring in some situations consolidated the paste fetching and parameter validation functions somewhat fixed some bugs with expiry handling hopefully haven't broken anything, changes are untested --- config.yml | 270 ++++++++++++++++++++++--------------------- lib/App/WerePaste.pm | 51 ++++---- 2 files changed, 164 insertions(+), 157 deletions(-) diff --git a/config.yml b/config.yml index d57e030..fcb5889 100644 --- a/config.yml +++ b/config.yml @@ -7,6 +7,9 @@ locale: "en_GB" logger: "console" log: "debug" +# Time in seconds between each paste expiry check +expire_every: 600 + template: "template_toolkit" engines: template: @@ -24,144 +27,145 @@ plugins: options: sqlite_unicode: 1 -# Comment out for production -show_errors: 1 +# Uncomment for debugging +#show_errors: 1 # Sets the expiration for posts # Options can be any combination of weeks, days, hours, minutes, seconds expiration: - weeks: 2 + weeks: 2 # Languages supported by Pygments +# TODO: perhaps swap this out with something in App::WerePaste::Util::PygmentsBridge so we can dynamically load supported languages languages: - - Programming languages: - - ActionScript: - - Ada: - - ANTLR: - - AppleScript: - - Assembly: nasm - - Asymptote: - - Awk: - - Bash: - - Befunge: - - Boo: - - BrainFuck: - - C: - - C++: - - C#: - - Clojure: - - CoffeeScript: - - ColdFusion: cfm - - Common Lisp: - - Coq: - - Cryptol: - - Cython: - - D: - - Dart: - - Delphi: - - Dylan: - - Erlang: - - Factor: - - Fancy: - - Fortran: - - F#: - - GAP: - - Gherkin: - - GL shaders: - - Groovy: - - Haskell: - - IDL: - - Io: - - Java: - - JavaScript: - - Lasso: - - LLVM: - - Logtalk: - - Lua: - - Matlab: - - MiniD: - - Modelica: - - Modula-2: - - MuPad: - - Nemerle: - - Nimrod: - - Objective-C: - - Objective-J: - - Octave: - - OCaml: - - PHP: - - Perl: - - PovRay: - - PostScript: - - PowerShell: - - Prolog: - - Python: - - REBOL: - - Red: - - Redcode: - - Ruby: - - Rust: - - R: - - S: - - S-Plus: - - Scala: - - Scheme: - - Scilab: - - Smalltalk: - - SNOBOL: - - Tcl: - - Vala: - - Verilog: - - VHDL: - - Visual Basic.NET: vbnet - - Visual FoxPro: foxpro - - XQuery: - - Zephir: - - Template Languages: - - Cheetah: - - Django: - - ERB: - - Genshi: - - Jinja: - - JSP: - - Mako: - - Myghty: - - Smarty: - - Tea: - - Configuration Markup: - - ApacheConf: - - INI-style: ini - - Lighttpd: - - Nginx: - - Other Markups: - - BBCode: - - CMake: - - CSS: - - Debian control file: control - - Diff: - - DTD: - - Gettext Catalogs: pot - - Gnuplot: - - Groff: - - HTML: - - HTTP Session: http - - IRC log (irssi-format): irc - - Makefile: - - MoinMoin/Trac wiki markup: moin - - MySQL: - - POV-Ray Scenes: pov - - Ragel: - - Redcode: - - ReST: - - SQL: - - PostgreSQL: psql - - SQLite: - - Squid Configuration: squid - - TeX: - - tcsh: - - VimScript: vim - - Windows Batch Script: bat - - XML: - - XSLT: - - YAML: + - Programming languages: + - ActionScript: + - Ada: + - ANTLR: + - AppleScript: + - Assembly: nasm + - Asymptote: + - Awk: + - Bash: + - Befunge: + - Boo: + - BrainFuck: + - C: + - C++: + - C#: + - Clojure: + - CoffeeScript: + - ColdFusion: cfm + - Common Lisp: + - Coq: + - Cryptol: + - Cython: + - D: + - Dart: + - Delphi: + - Dylan: + - Erlang: + - Factor: + - Fancy: + - Fortran: + - F#: + - GAP: + - Gherkin: + - GL shaders: + - Groovy: + - Haskell: + - IDL: + - Io: + - Java: + - JavaScript: + - Lasso: + - LLVM: + - Logtalk: + - Lua: + - Matlab: + - MiniD: + - Modelica: + - Modula-2: + - MuPad: + - Nemerle: + - Nimrod: + - Objective-C: + - Objective-J: + - Octave: + - OCaml: + - PHP: + - Perl: + - PovRay: + - PostScript: + - PowerShell: + - Prolog: + - Python: + - REBOL: + - Red: + - Redcode: + - Ruby: + - Rust: + - R: + - S: + - S-Plus: + - Scala: + - Scheme: + - Scilab: + - Smalltalk: + - SNOBOL: + - Tcl: + - Vala: + - Verilog: + - VHDL: + - Visual Basic.NET: vbnet + - Visual FoxPro: foxpro + - XQuery: + - Zephir: + - Template Languages: + - Cheetah: + - Django: + - ERB: + - Genshi: + - Jinja: + - JSP: + - Mako: + - Myghty: + - Smarty: + - Tea: + - Configuration Markup: + - ApacheConf: + - INI-style: ini + - Lighttpd: + - Nginx: + - Other Markups: + - BBCode: + - CMake: + - CSS: + - Debian control file: control + - Diff: + - DTD: + - Gettext Catalogs: pot + - Gnuplot: + - Groff: + - HTML: + - HTTP Session: http + - IRC log (irssi-format): irc + - Makefile: + - MoinMoin/Trac wiki markup: moin + - MySQL: + - POV-Ray Scenes: pov + - Ragel: + - Redcode: + - ReST: + - SQL: + - PostgreSQL: psql + - SQLite: + - Squid Configuration: squid + - TeX: + - tcsh: + - VimScript: vim + - Windows Batch Script: bat + - XML: + - XSLT: + - YAML: diff --git a/lib/App/WerePaste.pm b/lib/App/WerePaste.pm index 49258b1..68fca39 100644 --- a/lib/App/WerePaste.pm +++ b/lib/App/WerePaste.pm @@ -12,7 +12,7 @@ use Data::UUID; my $lastexpunge = 0; sub DeploySchema { - # need to find a way to handle this that doesn't shit errors everywhere + # TODO: figure out how to ensure schema is deployed without producing "table already exists" errors when it is already deployed eval {schema->deploy}; } sub DateTimeToQueryable { @@ -22,39 +22,47 @@ sub DateTimeToQueryable { } sub ExpirationToDate { my $expire = shift; - $expire = $expire ? { split ':', $expire } : undef; + $expire = $expire ? { split ':', $expire } : config->{default_expire}; return undef if $expire and $expire->{never}; - return DateTimeToQueryable(%{ $expire || config->{default_expire} }); + return DateTimeToQueryable(%{ $expire }); } sub GetUUID { my $uuid = Data::UUID->new->create_str; $uuid =~ s/\-//g; return lc $uuid; } -sub CheckExpired { - return unless time > ($lastexpunge+900); #expunge once every 15 mins +sub CheckExpiry { + return unless time > ($lastexpunge+config->{expire_every}); $lastexpunge = time; - schema->resultset('Paste')->search({ expiration => { '<' => DateTimeToQueryable() }})->delete_all; + schema->resultset('Paste')->search({expiration => { '<' => DateTimeToQueryable() }})->delete_all; } sub ValidateParams { my $params = shift; - if($params->{id}) { - return undef unless lc($params->{id}) =~ /^[a-f0-9]*$/; - return 1; - } return undef unless $params->{code}; + #TODO: Allow all 'word' characters rather than just a-zA-Z0-9, expanded grammar + ## Presently this is limited so people can't do anything nasty. return undef unless $params->{title} =~ /^[a-zA-Z0-9\.\-_ @\(\)]{0,255}$/; return undef unless $params->{lang} =~ /^[a-z0-9\.\-\+# ]{0,40}$/; return undef unless $params->{expiration} =~ /^([a-z]+:[0-9]+)(:[a-z]+:[0-9]+)*$/ or not $params->{expiration}; return 1; } sub GetPaste { - my $id = shift; - return schema->resultset('Paste')->single({ id => $id }) or return undef; + my $id = shift; $id = lc $id; + return undef unless $id =~ /^[a-f0-9]*$/; + #This got a bit messy, required because otherwise there are scenarios where an expired paste may still be viewed + return schema->resultset('Paste')->single({ + -and => [ + { id => $id }, + -or => [ + { expiration => { '>=' => DateTimeToQueryable() }}, + { expiration => undef } + ] + ]}) or return undef; } sub SubmitPaste { my $params = shift; my ($lang,$html) = PygmentsHighlight(lang => $params->{lang}, code => $params->{code}); + #TODO: maybe figure out a nicer way of doing this, presently the UUID namespace changes with every app start my $id = GetUUID(); my $result = schema->resultset('Paste')->create({ id => $id, @@ -66,31 +74,26 @@ sub SubmitPaste { }) or return undef; return $id; } -sub ValidateAndGet { - my $params = shift; - ValidateParams($params) or return undef; - return GetPaste(lc $params->{id}) or return undef; -} # Startup DeploySchema(); # Hooks -hook 'before' => sub { CheckExpired(); }; +hook 'before' => sub { CheckExpiry(); }; # Routes #get get '/' => sub { template 'index.tt'; }; -get '/:id' => sub { my $paste=ValidateAndGet(scalar params('route')) or pass; template 'show.tt', { paste => $paste };}; -get '/:id/copy' => sub { my $paste=ValidateAndGet(scalar params('route')) or pass; template 'index.tt', { paste => $paste }; }; -get '/:id/raw' => sub { my $paste=ValidateAndGet(scalar params('route')) or pass; content_type 'text/plain'; return $paste->code; }; +get '/:id' => sub { my $paste=GetPaste(scalar params 'route') or pass; template 'show.tt', { paste => $paste }; }; +get '/:id/copy' => sub { my $paste=GetPaste(scalar params 'route') or pass; template 'index.tt', { paste => $paste }; }; +get '/:id/raw' => sub { my $paste=GetPaste(scalar params 'route') or pass; content_type 'text/plain'; return $paste->code; }; #post post '/' => sub { - my $p = params('body'); - ValidateParams($p) or return send_error('Submitted paste is not valid. Check your post title and language, and try again.',400); + my $p = params 'body'; + ValidateParams($p) or return send_error('Submitted paste is not valid. Check your post title and language, and try again.', 400); my $id = SubmitPaste($p) or return redirect '/503.html'; return redirect "/$id"; }; #default -any qr/.*/ => sub { return send_error('Page gone',404); }; +any qr/.*/ => sub { return send_error('What you seek cannot be found here.', 404); }; 1; __END__