]> www.fi.muni.cz Git - paste.git/blobdiff - paste.pl
Download link
[paste.git] / paste.pl
index a750dfa6ecc70a745b11c6121fb5be8c5a1cee94..3eb13882f26ee372d18f19cf0db5fa6e3e8dfead 100755 (executable)
--- a/paste.pl
+++ b/paste.pl
@@ -37,7 +37,7 @@ post '/' => sub ($c) {
                $file_content = $upload->slurp;
        }
 
-       if ($filename !~ /\A\w[\w\.]*\.\w+\z/) {
+       if ($filename !~ /\A\w[\w-\.]*\.\w+\z/) {
                # print STDERR "FILENAME2 = " . $upload->filename . "\n";
                return $c->render(template => 'forbidden', status => 403);
        }
@@ -47,7 +47,7 @@ post '/' => sub ($c) {
 };
 
 get '/<filename>.<ext>'
-       => [ filename => qr/\w[\w\.]*/, ext => qr/\w+/ ]
+       => [ filename => qr/\w[\w-\.]*/, ext => qr/\w+/ ]
        => sub ($c) {
        my $fullname = $c->param('filename').'.'.$c->param('ext');
        my $file = $datadir->child($fullname);
@@ -56,9 +56,18 @@ get '/<filename>.<ext>'
        return $c->reply->not_found
                if !defined $stat;
 
+       if (defined $c->param('download')) {
+               $c->res->headers->content_disposition(
+                       "attachment; filename=$fullname"
+               );
+               $c->reply->file($file);
+               return;
+       }
        $c->stash(mtime => POSIX::strftime('%Y-%m-%d %H:%M:%S',
                localtime($stat->mtime)));
-       $c->stash(file_content => $file->slurp);
+       my $content = $file->slurp;
+       $content = Encode::decode('utf-8', $content);
+       $c->stash(file_content => $content);
        my $lang = $c->param('ext');
 
        $c->stash(language => "language-$lang");
@@ -98,7 +107,9 @@ __DATA__
 
 <h1><tt><%= $filename%>.<%= $ext %></tt>
    <span class="unimportant">— <%= config->{appname} %></span><br/>
-<small class="unimportant">Created: <%= $mtime %></small></h1>
+<small class="unimportant">Created: <%= $mtime %>
+<%= link_to "Download" => url_for->query(download => 1), class => 'downl' %>
+</small></h1>
 <pre><code class="<%= $language %>"><%= $file_content %></code></pre>
 
 
@@ -107,6 +118,10 @@ __DATA__
 
 <h1>Forbidden</h1>
 
+@@ not_found.html.ep
+% layout 'default';
+
+<h1>Not found!</h1>
 
 @@ layouts/default.html.ep
 <html>
@@ -116,10 +131,10 @@ __DATA__
     <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" />
     <meta name="viewport" content="width=device-width" />
 
-    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300italic,700,700italic">
+<!--    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300italic,700,700italic">-->
     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.css">
     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/milligram/1.4.1/milligram.css">
-    <link rel="icon" href="img/shebang-favicon.svg" />
+    <link rel="icon" href="favicon.svg" />
     <%= content 'header' %>
     <style>
       body {
@@ -141,8 +156,12 @@ __DATA__
       input {
         color: #f2f2f2;
       }
+      input[type="text"], input[type="password"] {
+        background-color: black;
+      }
       textarea {
         color: #f2f2f2;
+        background-color: black;
         font-family: monospace;
       }
       h1 small {
@@ -152,12 +171,15 @@ __DATA__
         color: #999;
       }
       pre {
-        border: 0;
+        border: 0.1rem solid #d1d1d1;
+        border-radius: .4rem;
       }
       pre code {
-        padding: 0;
+        padding: 1em;
         margin-left: 0;
         margin-right: 0;
+        background: black;
+        color: #aaa;
       }
       div.footer {
         color: #999;
@@ -166,14 +188,67 @@ __DATA__
       a {
         color: #90c0ff;
       }
+      a.downl {
+        display: inline-block;
+        float: right;
+      }
     </style>
     <title><%= config->{appname} %></title>
   </head>
   <body><div class="wrapper">
     <%= content %>
     <div class="footer">
-      Created by <b>Yenya's Paste Bin</b>,
-        <a href="https://www.fi.muni.cz/~kas/git/paste.git/">www.fi.muni.cz/~kas/git/paste</a>
+      <a href="https://www.fi.muni.cz/~kas/">Yenya</a>'s Paste Bin,
+      <a href="https://www.fi.muni.cz/~kas/git/paste.git/">www.fi.muni.cz/~kas/git/paste.git/</a>
     </div>
   </div></body>
 </html>
+
+@@ favicon.svg (base64)
+PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjwh
+LS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoK
+PHN2ZwogICB3aWR0aD0iMTkuOTc3NzIybW0iCiAgIGhlaWdodD0iMTkuOTc3NzIybW0iCiAgIHZp
+ZXdCb3g9IjAgMCAxOS45Nzc3MjEgMTkuOTc3NzIxIgogICB2ZXJzaW9uPSIxLjEiCiAgIGlkPSJz
+dmc1IgogICBpbmtzY2FwZTp2ZXJzaW9uPSIxLjEgKGM2OGUyMmMzODcsIDIwMjEtMDUtMjMpIgog
+ICBzb2RpcG9kaTpkb2NuYW1lPSJzaGViYW5nLWZhdmljb24uc3ZnIgogICB4bWxuczppbmtzY2Fw
+ZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgeG1sbnM6
+c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAu
+ZHRkIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnN2Zz0i
+aHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBp
+ZD0ibmFtZWR2aWV3NyIKICAgICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyY29sb3I9
+IiM2NjY2NjYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIgogICAgIGlua3NjYXBlOnBhZ2VzaGFk
+b3c9IjIiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdl
+Y2hlY2tlcmJvYXJkPSIwIgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJtbSIKICAgICBz
+aG93Z3JpZD0iZmFsc2UiCiAgICAgZml0LW1hcmdpbi10b3A9IjAiCiAgICAgZml0LW1hcmdpbi1s
+ZWZ0PSIwIgogICAgIGZpdC1tYXJnaW4tcmlnaHQ9IjAiCiAgICAgZml0LW1hcmdpbi1ib3R0b209
+IjAiCiAgICAgaW5rc2NhcGU6em9vbT0iMi42ODMyNDkyIgogICAgIGlua3NjYXBlOmN4PSIzMS4x
+MTg5ODgiCiAgICAgaW5rc2NhcGU6Y3k9IjMwLjkzMjY0NyIKICAgICBpbmtzY2FwZTp3aW5kb3ct
+d2lkdGg9IjE4MzUiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTA1MCIKICAgICBpbmtz
+Y2FwZTp3aW5kb3cteD0iNjUiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjAiCiAgICAgaW5rc2Nh
+cGU6d2luZG93LW1heGltaXplZD0iMSIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXll
+cjEiCiAgICAgaW5rc2NhcGU6c25hcC1wYWdlPSJ0cnVlIiAvPgogIDxkZWZzCiAgICAgaWQ9ImRl
+ZnMyIiAvPgogIDxnCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6
+Z3JvdXBtb2RlPSJsYXllciIKICAgICBpZD0ibGF5ZXIxIgogICAgIHRyYW5zZm9ybT0idHJhbnNs
+YXRlKC01NC41NjY5OTQsLTk3Ljk1MDE2NSkiPgogICAgPHJlY3QKICAgICAgIHN0eWxlPSJmaWxs
+OiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjIuMDI5MDQ7
+c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZz
+ZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgaWQ9InJlY3QxMjk0OSIKICAgICAgIHdpZHRo
+PSIxOS45Nzc3MjIiCiAgICAgICBoZWlnaHQ9IjE5Ljk3NzcyMiIKICAgICAgIHg9IjU0LjU2Njk5
+NCIKICAgICAgIHk9Ijk3Ljk1MDE2NSIKICAgICAgIHJ5PSIwLjUzNjg1NTI4IiAvPgogICAgPHRl
+eHQKICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpu
+b3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpib2xkO2ZvbnQtc3RyZXRjaDpu
+b3JtYWw7Zm9udC1zaXplOjE3LjE3OTJweDtsaW5lLWhlaWdodDoxMjUlO2ZvbnQtZmFtaWx5OidE
+ZWphVnUgU2FucyBNb25vJzstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidEZWphVnUgU2Fu
+cyBNb25vIEJvbGQnO3RleHQtYWxpZ246c3RhcnQ7bGV0dGVyLXNwYWNpbmc6MHB4O3dvcmQtc3Bh
+Y2luZzowcHg7dGV4dC1hbmNob3I6c3RhcnQ7ZmlsbDojMDBmZmZmO2ZpbGwtb3BhY2l0eToxO3N0
+cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjUzNjg0OXB4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ry
+b2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICB4PSI1NS44NTM0MDki
+CiAgICAgICB5PSIxMTQuMTE5OSIKICAgICAgIGlkPSJ0ZXh0NzgxIj48dHNwYW4KICAgICAgICAg
+c29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgaWQ9InRzcGFuNzc5IgogICAgICAgICBzdHls
+ZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpib2xk
+O2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjE3LjE3OTJweDtmb250LWZhbWlseTonRGVq
+YVZ1IFNhbnMgTW9ubyc7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonRGVqYVZ1IFNhbnMg
+TW9ubyBCb2xkJztmaWxsOiMwMGZmZmY7c3Ryb2tlLXdpZHRoOjAuNTM2ODQ5cHgiCiAgICAgICAg
+IHg9IjU1Ljg1MzQwOSIKICAgICAgICAgeT0iMTE0LjExOTkiPiMhPC90c3Bhbj48L3RleHQ+CiAg
+PC9nPgo8L3N2Zz4K
+