]> www.fi.muni.cz Git - paste.git/commitdiff
Initial revision
authorJan "Yenya" Kasprzak <kas@fi.muni.cz>
Sat, 20 Nov 2021 23:03:44 +0000 (00:03 +0100)
committerJan "Yenya" Kasprzak <kas@fi.muni.cz>
Sat, 20 Nov 2021 23:03:44 +0000 (00:03 +0100)
config.yml.sample [new file with mode: 0644]
paste.pl [new file with mode: 0755]

diff --git a/config.yml.sample b/config.yml.sample
new file mode 100644 (file)
index 0000000..94aea6b
--- /dev/null
@@ -0,0 +1,5 @@
+---
+# Password for uploads. If not set, uploads should be done by other means,
+# such as direct writing to data directory
+password: change_this
+# base: https://external.name/prefix
diff --git a/paste.pl b/paste.pl
new file mode 100755 (executable)
index 0000000..6c25fde
--- /dev/null
+++ b/paste.pl
@@ -0,0 +1,178 @@
+#!/usr/bin/perl
+
+use Mojolicious::Lite -signatures;
+use Mojo::File qw(curfile);
+
+plugin NotYAMLConfig => { file => 'config.yml',
+       default => {
+               appname => 'Paste Bin',
+       } };
+
+my $datadir = curfile->sibling('data');
+if (app->config->{datadir}) {
+       $datadir = Mojo::File->new(app->config->{datadir});
+}
+
+chdir curfile->dirname;
+
+get '/' => sub ($c) {
+       $c->render(template => 'forbidden', status => 403)
+               if !length app->config->{password};
+} => 'index';
+
+post '/' => sub ($c) {
+       # print STDERR "pass=" . $c->param('password') . "\n";
+       return $c->render(template => 'forbidden', status => 403)
+               if !defined app->config->{password}
+                       || !length $c->param('password')
+                       || $c->param('password') ne app->config->{password};
+
+       my $file_content = $c->param('text');
+       my $filename = $c->param('filename');
+       my $upload = $c->param('file');
+
+       if (defined $upload && $upload->size) {
+               # print STDERR "FILENAME = " . $upload->filename . "\n";
+               $filename = $upload->filename;
+               $file_content = $upload->slurp;
+       }
+
+       if ($filename !~ /\A\w[\w\.]*\.\w+\z/) {
+               # print STDERR "FILENAME2 = " . $upload->filename . "\n";
+               return $c->render(template => 'forbidden', status => 403);
+       }
+
+       $datadir->child($filename)->spurt($file_content);
+       $c->redirect_to($c->req->url->base . "$filename");
+};
+
+get '/<filename>.<ext>'
+       => [ filename => qr/\w[\w\.]*/, ext => qr/\w+/ ]
+       => sub ($c) {
+       my $fullname = $c->param('filename').'.'.$c->param('ext');
+       my $file = $datadir->child($fullname);
+       my $stat = $file->stat;
+       
+       return $c->reply->not_found
+               if !defined $stat;
+
+       $c->stash(mtime => POSIX::strftime('%Y-%m-%d %H:%M:%S',
+               localtime($stat->mtime)));
+       $c->stash(file_content => $file->slurp);
+       my $lang = $c->param('ext');
+
+       $c->stash(language => "language-$lang");
+       $c->render;
+} => 'default';
+
+app->start;
+
+__DATA__
+@@ index.html.ep
+% layout 'default';
+<h1><%= config->{appname} %></h1>
+<form method="POST" enctype="multipart/form-data">
+<label for="text">Enter some text or source code here:</label>
+<textarea name="text" id="input_text">
+</textarea>
+<label for="file">Or select a file to upload:</label>
+<input type="file" name="file"/>
+<label for="filename">Name the file:</label>
+<input type="text" name="filename"/>
+<label for="password">Password:</label>
+<input type="password" name="password" />
+<input type="submit" value="Submit"/>
+</form>
+
+
+@@ default.html.ep
+% layout 'default';
+
+%= content_for header => begin
+    <base href="<%= config->{base} %>/">
+    <link rel="stylesheet" href="highlight/qtcreator-dark.min.css">
+    <script src="highlight/highlight.min.js"></script>
+    <script>hljs.highlightAll();</script>
+% end
+
+<h1><tt><%= $filename%>.<%= $ext %></tt>
+   <span class="unimportant">— <%= config->{appname} %></span><br/>
+<small class="unimportant">Created: <%= $mtime %></small></h1>
+<pre><code class="<%= $language %>"><%= $file_content %></code></pre>
+
+
+@@ forbidden.html.ep
+% layout 'default';
+
+<h1>Forbidden</h1>
+
+
+@@ layouts/default.html.ep
+<html>
+  <head>
+    <meta charset="utf-8" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+    <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://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" />
+    <%= content 'header' %>
+    <style>
+      body {
+        background: #1c1f24;
+        color: #f2f2f2;
+      }
+      .wrapper {
+        max-width: 90rem;
+        margin: 0 auto;
+        margin-top: 1.5rem;
+      }
+      #input_text {
+        height: 40%;
+      }
+      .button, input[type="submit"] {
+        background-color: #0030c0;
+        border-color: #202080;
+      }
+      input {
+        color: #f2f2f2;
+      }
+      textarea {
+        color: #f2f2f2;
+        font-family: monospace;
+      }
+      h1 small {
+        font-size: 2.0rem;
+      }
+      .unimportant {
+        color: #999;
+      }
+      pre {
+        border: 0;
+      }
+      pre code {
+        padding: 0;
+        margin-left: 0;
+        margin-right: 0;
+      }
+      div.footer {
+        color: #999;
+        text-align: right;
+      } 
+      a {
+        color: #90c0ff;
+      }
+    </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/">www.fi.muni.cz/~kas/git/paste</a>
+    </div>
+  </div></body>
+</html>