Parcourir la source

Add hastebin Dockerfile

dennisro il y a 7 ans
Parent
commit
3d1cd835bc

+ 27 - 0
data/Dockerfiles/hastebin/Dockerfile

@@ -0,0 +1,27 @@
+FROM node:8.1-alpine
+
+ENV REDIS_HOST=0.0.0.0
+ENV STORAGE_TYPE=file 
+ENV UID=791 GID=791
+
+EXPOSE 7777
+
+COPY run.sh /usr/local/bin/run.sh
+COPY about.md /hastebin/about.md
+COPY haste.py /hastebin/haste.py
+
+WORKDIR /hastebin
+
+RUN set -xe \
+    && apk add -U --no-cache --virtual .build-deps zip unzip ca-certificates openssl \
+    && apk add -U --no-cache su-exec busybox \
+    && wget https://github.com/seejohnrun/haste-server/archive/master.zip \
+    && unzip master.zip \
+    && find haste-server-master -mindepth 1 -maxdepth 1 -print0 | xargs -0 -i mv {} /hastebin \
+    && rmdir haste-server-master \
+    && rm master.zip \
+    && npm install \
+    && chmod +x -R /usr/local/bin/run.sh \
+    && apk del .build-deps
+
+CMD ["run.sh"]

+ 59 - 0
data/Dockerfiles/hastebin/README.md

@@ -0,0 +1,59 @@
+### Thanks to [https://github.com/nrobinaubertin/dockerfiles/tree/master/hastebin](nrobinaubertin) for this Dockerfile. Original README below
+
+Hastebin
+========
+*Simple, lightweight and secure Hastebin container based on Alpine Linux*
+
+![hastebin](hastebin.png)
+
+### What is hastebin ?
+[hastebin](https://hastebin.com/about.md) is the prettiest, easiest to use pastebin ever made. It is used to share text and can be used from the command line with the hastebin-client. You can find the server repo [here](https://github.com/seejohnrun/haste-server).
+
+### Goal of this container
+Propose a lightweight and secure container that is easy to setup.
+
+### Features
+- Based on Alpine Linux.
+- No Root processes, as secure as possible.
+- You can choose your storage type
+
+### Run-time variables
+- **STORAGE_TYPE**: (Optional) Type of storage ("file" or "redis")
+- **REDIS_HOST**: (Optional) The ip of the redis db
+- **UID**: (Optional) The UID executing the server
+- **GID**: (Optional) The GID executing the server
+
+### Ports
+- **7777**
+
+### Setup
+Build this image:
+```
+docker build -t hastebin .
+```
+Now, you have two choices:
+
+**1) Using internal file storage**  
+This is the easyiest to set up. You just need to run:
+```
+docker run -d --name hastebin hastebin
+```
+
+**2) Using redis as storage**  
+This will allow you to backup your data.
+You need redis to store the data of this hastebin container:
+```
+docker run -d --name hastebin-redis redis:alpine
+```
+You can check the ip address of the hastebin-redis container with:
+```
+docker network inspect bridge
+```
+Then you just have to start the container, linking it to the hastebin-redis instance:
+```
+docker run -d -e STORAGE_TYPE=redis -e REDIS_HOST=172.17.0.2 --name hastebin --init hastebin
+```
+
+### Bonus script
+I've made a python 3 script to send/get and encrypt/decrypt snippets.  
+You can find it [here](haste.py).

+ 66 - 0
data/Dockerfiles/hastebin/about.md

@@ -0,0 +1,66 @@
+# Haste
+
+Sharing code is a good thing, and it should be _really_ easy to do it.
+A lot of times, I want to show you something I'm seeing - and that's where we
+use pastebins.
+
+Haste is the prettiest, easiest to use pastebin ever made.
+
+## Basic Usage
+
+Type what you want me to see, click "Save", and then copy the URL.  Send that
+URL to someone and they'll see what you see.
+
+To make a new entry, click "New" (or type 'control + n')
+
+## From the Console
+
+Most of the time I want to show you some text, it's coming from my current
+console session.  We should make it really easy to take code from the console
+and send it to people.
+
+`cat something | haste` # http://hastebin.com/1238193
+
+You can even take this a step further, and cut out the last step of copying the
+URL with:
+
+* osx: `cat something | haste | pbcopy`
+* linux: `cat something | haste | xsel`
+* windows: check out [WinHaste](https://github.com/ajryan/WinHaste)
+
+After running that, the STDOUT output of `cat something` will show up at a URL
+which has been conveniently copied to your clipboard.
+
+That's all there is to that, and you can install it with `gem install haste`
+right now.
+  * osx: you will need to have an up to date version of Xcode
+  * linux: you will need to have rubygems and ruby-devel installed
+
+Or you can use a python version of this script that will allow you to do all this and also encrypt/decrypt your snippets !
+You can find the script at the "haste.py" paste.
+
+## Duration
+
+Pastes will stay for 30 days from their last view.  They may be removed earlier
+and without notice.
+
+## Privacy
+
+While the contents of hastebin.com are not directly crawled by any search robot
+that obeys "robots.txt", there should be no great expectation of privacy.  Post
+things at your own risk. Not responsible for any loss of data or removed
+pastes.
+
+You can encrypt your snippets for increased privacy by using the above python script.
+
+## Open Source
+
+Haste can easily be installed behind your network, and it's all open source!
+
+* [haste-client](https://github.com/seejohnrun/haste-client)
+* [haste-server](https://github.com/seejohnrun/haste-server)
+
+## Author
+
+Code by John Crepezzi <john.crepezzi@gmail.com>
+Key Design by Brian Dawson <bridawson@gmail.com>

+ 173 - 0
data/Dockerfiles/hastebin/haste.py

@@ -0,0 +1,173 @@
+#!/usr/bin/env python
+
+# initially stolen from: https://github.com/jirutka/haste-client
+# adapted to be only for python 3
+# added get snippet feature and crypt snippet feature
+# change the server url in CONFIG if needed
+
+"""
+haste - a CLI client for Haste server.
+
+Usage:
+    haste send [-r] [--password=<pwd>] [FILE]
+    haste get [--password=<pwd>] KEY
+
+Options:
+    -r --raw            Return a URL to the raw paste data.
+    --password=<pwd>    Encrypt/decrypt message using <pwd> as password.
+    -h --help           Show this message.
+    -v --version        Show version.
+
+If FILE is not specified, haste will read from standard input.
+"""
+
+import os
+from base64 import b64decode, b64encode
+import json
+import sys
+import docopt
+import requests
+from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
+from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
+from cryptography.hazmat.backends import default_backend
+_BACKEND = default_backend()
+
+__version__ = '2.0.1'
+
+CONFIG = {
+    'server_url': "https://hastebin.com",
+    'timeout': 3
+}
+
+def main(**kwargs):
+    """ main function: do actions following args """
+
+    if kwargs['KEY'] and kwargs['get']:
+        data = get_snippet(kwargs['KEY'], CONFIG['server_url'], CONFIG['timeout'])
+        if kwargs['--password']:
+            data = decrypt(kwargs['--password'], json.loads(data)).decode("utf-8")
+        print(data)
+    elif kwargs['send']:
+        data = read_file(kwargs['FILE']) if kwargs['FILE'] else read_stdin()
+        if kwargs['--password']:
+            data = json.dumps(encrypt(kwargs['--password'], data))
+        url = create_snippet(data, CONFIG['server_url'], CONFIG['timeout'], kwargs['--raw'])
+        print(url)
+    else:
+        print(docopt.docopt(__doc__))
+
+def get_snippet(dockey, baseurl, timeout):
+    """ get a snippet from the server """
+    try:
+        url = baseurl + "/raw/" + dockey
+        response = requests.get(url, timeout=float(timeout))
+    except requests.exceptions.Timeout:
+        exit("Error: connection timed out")
+
+    return response.text
+
+def create_snippet(data, baseurl, timeout, raw):
+    """
+    Creates snippet with the given data on the haste server specified by the
+    baseurl and returns URL of the created snippet.
+    """
+    try:
+        url = baseurl + "/documents"
+        response = requests.post(url, data.encode('utf-8'), timeout=float(timeout))
+    except requests.exceptions.Timeout:
+        exit("Error: connection timed out")
+
+    dockey = json.loads(response.text)['key']
+    return baseurl + ("/raw/" if raw else "/") + dockey
+
+def read_stdin():
+    """ joins lines of stdin into a single string """
+    return "".join(sys.stdin.readlines()).strip()
+
+def read_file(path):
+    """ reads lines of a file and joins them into a single string """
+    try:
+        with open(path, 'r') as text_file:
+            return "".join(text_file.readlines()).strip()
+    except IOError:
+        exit("Error: file '%s' is not readable!" % path)
+
+def decrypt(pwd, data):
+    """ Decrypt using password and input json """
+
+    ct = b64decode(data['ct'])
+    salt = b64decode(data['salt'])
+    tag_start = len(ct) - data['ts'] // 8
+    tag = ct[tag_start:]
+    ciphertext = ct[:tag_start]
+
+    mode_class = getattr(modes, data['mode'].upper())
+    algo_class = getattr(algorithms, data['cipher'].upper())
+
+    kdf = _kdf(data['ks'], iters=data['iter'], salt=salt)[0]
+    key = kdf.derive(bytes(pwd, "utf-8"))
+    cipher = Cipher(
+        algo_class(key),
+        mode_class(
+            b64decode(data['iv']),
+            tag,
+            min_tag_length=data['ts'] // 8
+        ),
+        backend=_BACKEND
+    )
+
+    dec = cipher.decryptor()
+    return dec.update(ciphertext) + dec.finalize()
+
+def _kdf(keysize=128, iters=256000, salt=None):
+    """ Returns a key derivation function: used to create a strong key based on the input """
+    kdf_salt = salt or os.urandom(8)
+    kdf = PBKDF2HMAC(
+        algorithm=hashes.SHA256(),
+        length=keysize // 8,
+        salt=kdf_salt,
+        iterations=iters,
+        backend=_BACKEND
+    )
+
+    return kdf, kdf_salt
+
+def encrypt(pwd, plaintext, mode='gcm', keysize=128, tagsize=128, iters=256000):
+    """ Encrypt plain text using password. Outputs json """
+
+    ts = tagsize // 8
+
+    mode_class = getattr(modes, mode.upper())
+    algo_class = getattr(algorithms, 'AES')
+
+    iv = os.urandom(16)
+    kdf, salt = _kdf(keysize, iters)
+    bpwd = str.encode(pwd)
+    key = kdf.derive(bpwd)
+    cipher = Cipher(
+        algo_class(key),
+        mode_class(iv, min_tag_length=ts),
+        backend=_BACKEND
+    )
+
+    enc = cipher.encryptor()
+    btext = str.encode(plaintext)
+    ciphertext = enc.update(btext) + enc.finalize()
+    output = {
+        "v": 1,
+        "iv": b64encode(iv).decode("utf-8"),
+        "salt": b64encode(salt).decode("utf-8"),
+        "ct": b64encode(ciphertext + enc.tag[:ts]).decode("utf-8"),
+        "iter": iters,
+        "ks": keysize,
+        "ts": tagsize,
+        "mode": mode,
+        "cipher": 'aes',
+        "adata": ""
+    }
+    return output
+
+DOC = docopt.docopt(__doc__, version='haste ' + __version__)
+if __name__ == "__main__":
+    main(**DOC)

BIN
data/Dockerfiles/hastebin/hastebin.png


+ 64 - 0
data/Dockerfiles/hastebin/run.sh

@@ -0,0 +1,64 @@
+#!/bin/sh
+
+set -xe
+
+echo '
+{
+  "host": "0.0.0.0",
+  "port": 7777,
+  "keyLength": 6,
+  "maxLength": 400000,
+  "staticMaxAge": 86400,
+  "recompressStaticAssets": true,
+  "logging": [
+    {
+      "level": "verbose",
+      "type": "Console",
+      "colorize": true
+    }
+  ],
+  "keyGenerator": {
+    "type": "random"
+  },
+  "rateLimits": {
+    "categories": {
+      "normal": {
+        "totalRequests": 500,
+        "every": 60000
+      }
+    }
+  },
+  "documents": {
+    "about": "/hastebin/about.md",
+    "haste": "/hastebin/haste.py"
+  },
+' > config.js
+
+if [ "$STORAGE_TYPE" = "file" ]
+then
+    echo '
+        "storage": {
+          "path": "/hastebin/data",
+          "type": "file"
+        }
+    ' >> config.js
+fi
+
+if [ "$STORAGE_TYPE" = "redis" ]
+then
+    npm install redis
+    echo '
+      "storage": {
+        "type": "redis",
+        "host": "'"${REDIS_HOST}"'",
+        "port": 6379,
+        "db": 2,
+        "expire": 2592000
+      }
+    ' >> config.js
+fi
+
+echo '}' >> config.js
+
+chown "$UID:$GID" -R /hastebin
+su-exec "$UID:$GID" npm start