3 use Mojolicious::Lite -signatures;
4 use Mojo::File qw(curfile);
6 plugin NotYAMLConfig => { file => 'config.yml',
8 appname => 'Paste Bin',
11 my $datadir = curfile->sibling('data');
12 if (app->config->{datadir}) {
13 $datadir = Mojo::File->new(app->config->{datadir});
16 chdir curfile->dirname;
19 $c->render(template => 'forbidden', status => 403)
20 if !length app->config->{password};
23 post '/' => sub ($c) {
24 # print STDERR "pass=" . $c->param('password') . "\n";
25 return $c->render(template => 'forbidden', status => 403)
26 if !defined app->config->{password}
27 || !length $c->param('password')
28 || $c->param('password') ne app->config->{password};
30 my $file_content = $c->param('text');
31 my $filename = $c->param('filename');
32 my $upload = $c->param('file');
34 if (defined $upload && $upload->size) {
35 # print STDERR "FILENAME = " . $upload->filename . "\n";
36 $filename = $upload->filename;
37 $file_content = $upload->slurp;
40 if ($filename !~ /\A\w[\w\.]*\.\w+\z/) {
41 # print STDERR "FILENAME2 = " . $upload->filename . "\n";
42 return $c->render(template => 'forbidden', status => 403);
45 $datadir->child($filename)->spurt($file_content);
46 $c->redirect_to($c->req->url->base . "$filename");
49 get '/<filename>.<ext>'
50 => [ filename => qr/\w[\w\.]*/, ext => qr/\w+/ ]
52 my $fullname = $c->param('filename').'.'.$c->param('ext');
53 my $file = $datadir->child($fullname);
54 my $stat = $file->stat;
56 return $c->reply->not_found
59 $c->stash(mtime => POSIX::strftime('%Y-%m-%d %H:%M:%S',
60 localtime($stat->mtime)));
61 $c->stash(file_content => $file->slurp);
62 my $lang = $c->param('ext');
64 $c->stash(language => "language-$lang");
73 <h1><%= config->{appname} %></h1>
74 <form method="POST" enctype="multipart/form-data">
75 <label for="text">Enter some text or source code here:</label>
76 <textarea name="text" id="input_text">
78 <label for="file">Or select a file to upload:</label>
79 <input type="file" name="file"/>
80 <label for="filename">Name the file:</label>
81 <input type="text" name="filename"/>
82 <label for="password">Password:</label>
83 <input type="password" name="password" />
84 <input type="submit" value="Submit"/>
91 %= content_for header => begin
92 <base href="<%= config->{base} %>/">
93 <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/styles/qtcreator-dark.min.css">
94 <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/highlight.min.js"></script>
95 <script>hljs.highlightAll();</script>
98 <h1><tt><%= $filename%>.<%= $ext %></tt>
99 <span class="unimportant">— <%= config->{appname} %></span><br/>
100 <small class="unimportant">Created: <%= $mtime %></small></h1>
101 <pre><code class="<%= $language %>"><%= $file_content %></code></pre>
110 @@ layouts/default.html.ep
113 <meta charset="utf-8" />
114 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
115 <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" />
116 <meta name="viewport" content="width=device-width" />
118 <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300italic,700,700italic">
119 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.css">
120 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/milligram/1.4.1/milligram.css">
121 <link rel="icon" href="img/shebang-favicon.svg" />
122 <%= content 'header' %>
136 .button, input[type="submit"] {
137 background-color: #0030c0;
138 border-color: #202080;
145 font-family: monospace;
169 <title><%= config->{appname} %></title>
171 <body><div class="wrapper">
174 Created by <b>Yenya's Paste Bin</b>,
175 <a href="https://www.fi.muni.cz/~kas/git/paste/">www.fi.muni.cz/~kas/git/paste</a>