summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChloe Kudryavtsev <toast@toastin.space>2019-02-26 00:05:16 -0500
committerChloe Kudryavtsev <toast@toastin.space>2019-02-26 00:05:16 -0500
commitbd838f52f57ffee922f25b8dfbb6e75700f85a11 (patch)
tree13a2ecf2dc09aa12499626876c1edb6ec1d03aa1
Initial draft version
-rw-r--r--.gitignore15
-rw-r--r--LICENSE22
-rw-r--r--dub.sdl6
-rw-r--r--dub.selections.json18
-rw-r--r--source/app.d22
-rw-r--r--source/hash.d13
-rw-r--r--source/package.d3
-rw-r--r--source/web.d64
-rw-r--r--views/code.dt23
-rw-r--r--views/index.dt37
-rw-r--r--views/layout.dt27
11 files changed, 250 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2676d76
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+.dub
+docs.json
+__dummy.html
+docs/
+/brpaste
+brpaste.so
+brpaste.dylib
+brpaste.dll
+brpaste.a
+brpaste.lib
+brpaste-test-*
+*.exe
+*.o
+*.obj
+*.lst
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..fa84bf4
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+MIT License
+
+Copyright (c) 2019 Chloe Kudryavtsev
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/dub.sdl b/dub.sdl
new file mode 100644
index 0000000..8c32044
--- /dev/null
+++ b/dub.sdl
@@ -0,0 +1,6 @@
+name "brpaste"
+description "A pastebin server so fast, it burns rubber."
+authors "Chloe Kudryavtsev"
+copyright "Copyright © 2019, Chloe Kudryavtsev"
+license "MIT"
+dependency "vibe-d" version="~>0.8.5-beta.2"
diff --git a/dub.selections.json b/dub.selections.json
new file mode 100644
index 0000000..a963d46
--- /dev/null
+++ b/dub.selections.json
@@ -0,0 +1,18 @@
+{
+ "fileVersion": 1,
+ "versions": {
+ "botan": "1.12.10",
+ "botan-math": "1.0.3",
+ "diet-ng": "1.5.0",
+ "eventcore": "0.8.41",
+ "libasync": "0.8.3",
+ "libevent": "2.0.2+2.0.16",
+ "memutils": "0.4.13",
+ "mir-linux-kernel": "1.0.1",
+ "openssl": "1.1.6+1.0.1g",
+ "stdx-allocator": "2.77.5",
+ "taggedalgebraic": "0.11.3",
+ "vibe-core": "1.6.0",
+ "vibe-d": "0.8.5-beta.2"
+ }
+}
diff --git a/source/app.d b/source/app.d
new file mode 100644
index 0000000..7b7c3fd
--- /dev/null
+++ b/source/app.d
@@ -0,0 +1,22 @@
+import brpaste;
+
+import vibe.d;
+
+int main(string[] args)
+{
+ auto settings = new HTTPServerSettings;
+ settings.port = 8080;
+ settings.bindAddresses = [];
+
+ readOption("bind|b", &settings.bindAddresses, "Sets the address to bind to");
+ readOption("port|p", &settings.port, "Sets the port to listen on");
+ if(settings.bindAddresses.length == 0) settings.bindAddresses = [ "127.0.0.1" ];
+
+ auto router = new URLRouter;
+ router.registerWebInterface(new BRPaste);
+ listenHTTP(settings, router);
+
+ import std.conv;
+ logInfo("Please open http://%s:%d/ in your browser.", settings.bindAddresses[0], settings.port);
+ return runApplication();
+}
diff --git a/source/hash.d b/source/hash.d
new file mode 100644
index 0000000..3071fa3
--- /dev/null
+++ b/source/hash.d
@@ -0,0 +1,13 @@
+module brpaste.hash;
+
+pure string hash(T)(T data) {
+ import std.base64;
+ import std.digest.murmurhash;
+ auto hash = digest!(MurmurHash3!32)(data);
+ return Base64URLNoPadding.encode(hash);
+}
+
+pure string hash(T : string)(T data) {
+ import std.string;
+ return hash(data.representation);
+}
diff --git a/source/package.d b/source/package.d
new file mode 100644
index 0000000..cc9ed08
--- /dev/null
+++ b/source/package.d
@@ -0,0 +1,3 @@
+module brpaste;
+
+public import brpaste.web;
diff --git a/source/web.d b/source/web.d
new file mode 100644
index 0000000..ca3b644
--- /dev/null
+++ b/source/web.d
@@ -0,0 +1,64 @@
+module brpaste.web;
+
+import brpaste.hash;
+
+import vibe.vibe;
+
+RedisDatabase client;
+shared static this() {
+ string path = "redis://127.0.0.1";
+ readOption("redis|r", &path, "The URL to use to connect to redis");
+ URL redis = path;
+ client = connectRedisDB(redis);
+}
+
+class BRPaste {
+ @method(HTTPMethod.REPORT)
+ @path("/health")
+ void health(HTTPServerResponse res) {
+ import std.array;
+ res.statusCode = 200;
+ auto app = appender!string;
+
+ // is Redis healthy? - FIXME: stack traces over HTTP are fun, I guess
+ import std.random;
+ long val = uniform!uint;
+ auto ech = client.client.echo!(long, long)(val);
+ if(val != ech) {
+ res.statusCode = 500;
+ app.put("Redis: failed.");
+ } else app.put("Redis: pass.");
+
+ res.writeBody(app.data);
+ }
+
+ void index() {
+ render!("index.dt");
+ }
+
+ @path("/:id")
+ void getId(string _id) {
+ if (!client.exists(_id)) throw new HTTPStatusException(404);
+ string language;
+ // TODO: rewrite the next two lines once #2273 is resolved
+ auto req = request;
+ if (req.query.length > 0) language = req.query.byKey.front;
+ auto data = client.get(_id);
+ render!("code.dt", data, language);
+ }
+
+ @path("/raw/:id")
+ void getRawId(HTTPServerResponse res, string _id) {
+ if (!client.exists(_id)) throw new HTTPStatusException(404);
+ auto val = client.get(_id);
+ res.contentType = "text/plain";
+ res.writeBody(val);
+ }
+
+ void post(string data) {
+ auto hash = data.hash;
+ client.set(hash, data);
+ status(201);
+ response.writeBody(hash);
+ }
+}
diff --git a/views/code.dt b/views/code.dt
new file mode 100644
index 0000000..255af74
--- /dev/null
+++ b/views/code.dt
@@ -0,0 +1,23 @@
+extends layout
+
+block css
+block scripts
+ - string prefix = "https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0";
+ link(rel='stylesheet', crossorigin='anonymous',
+ href='#{prefix}/themes/prism.min.css')
+block bodyscripts
+ script(
+ src='#{prefix}/prism.min.js')
+ - import std.array;
+ - if(!language.empty)
+ script(
+ src='#{prefix}/components/prism-#{language}.min.js')
+
+block content
+ pre
+ - import std.array;
+ - string lang = "none";
+ - if (!language.empty) lang = language;
+ code(class='language-#{lang}')= data
+
+//- vim: ft=pug
diff --git a/views/index.dt b/views/index.dt
new file mode 100644
index 0000000..24136ff
--- /dev/null
+++ b/views/index.dt
@@ -0,0 +1,37 @@
+extends layout
+
+block content
+ h1 Burning Rubber Paste
+ h2 Usage
+ table(border='1')
+ thead: tr
+ th Method - Endpoint
+ th Effect
+ tbody
+ tr
+ td: pre: code POST /data=anything
+ td Pastebin anything
+ tr
+ td: pre: code GET /id
+ td Read paste with ID "id"
+ tr
+ td: pre: code GET /id?lang
+ td Read paste with ID "id", and highlight it as "lang"
+ tr
+ td: pre: code GET /raw/id
+ td Get the raw contents of paste with ID "id"
+ h2 Examples
+ pre: code(class='language-sh')
+ | curl -X POST -F 'sprunge=<-' https://brpaste.example.com
+ | http -f POST https://brpaste.example.com data=@file.txt
+ | curl https://brpaste.example.com/raw/some_id
+ | xdg-open https://brpaste.example.com/some_id?cpp
+ h2 Paste from a browser
+ form(action='/', method='post')
+ textarea(name='data', autocomplete='off',
+ required, autofocus,
+ cols='80', rows='27')
+ br
+ button(type='submit') Paste it!
+
+//- vim: ft=pug
diff --git a/views/layout.dt b/views/layout.dt
new file mode 100644
index 0000000..6b213a6
--- /dev/null
+++ b/views/layout.dt
@@ -0,0 +1,27 @@
+doctype html
+html(lang='en')
+ head
+ meta(charset='utf-8')
+ meta(name='viewport', content='width=device-width, initial-scale=1')
+ block css
+ :css
+ body {
+ margin: 40px auto;
+ max-width: 650px;
+ line-height: 1.6;
+ font-size: 18px;
+ color: #444;
+ padding: 0 10px
+ }
+ h1,h2,h3 { line-height:1.2; }
+ td { text-align: left; }
+ block scripts
+ block title
+ title Burning Rubber Paste
+ body
+ #main
+ block content
+ p I'm not sure how you got here, but you shouldn't be here.
+ block bodyscripts
+
+//- vim: ft=pug