From 4bacc019380c8dbe834209816ae9a956ab62a739 Mon Sep 17 00:00:00 2001 From: klml Date: Wed, 15 Dec 2021 17:22:07 +0100 Subject: [PATCH 01/36] version bump python 3.10.1-alpine --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 32bc640..3ee2f44 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.9.6-alpine +FROM python:3.10.1-alpine WORKDIR /app COPY . /app From d4650a5da643dd18f276012c6a3a47c91f357f75 Mon Sep 17 00:00:00 2001 From: klml Date: Wed, 15 Dec 2021 17:26:31 +0100 Subject: [PATCH 02/36] version https://www.w3.org/blog/2007/05/html-and-version-mechanisms/ --- index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/index.html b/index.html index f4456a0..cd52d25 100644 --- a/index.html +++ b/index.html @@ -6,6 +6,7 @@ message split +
From 587c0169db13ea8235b32cddf330fd1520eb7bd8 Mon Sep 17 00:00:00 2001 From: klml Date: Wed, 15 Dec 2021 20:41:59 +0100 Subject: [PATCH 03/36] erinome config log --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index afe92e4..2ba2135 100644 --- a/README.md +++ b/README.md @@ -79,9 +79,10 @@ command=python3 /home/msgsplit/msgsplit/msgsplit.py autostart=yes autorestart=yes [msgsplit@erinome ~]$ supervisorctl status -msgsplit RUNNING pid 29057, uptime 0:25:35 +msgsplit RUNNING pid 17680, uptime 1:33:05 [msgsplit@erinome ~]$ uberspace web backend list -/writeread http:8080 => OK, listening: PID 29057, python3 /home/msgsplit/msgsplit/msgsplit.py +/writeserver http:8080 => OK, listening: PID 17680, python3 /home/msgsplit/msgsplit/msgsplit.py +/readserver http:8080 => OK, listening: PID 17680, python3 /home/msgsplit/msgsplit/msgsplit.py / apache (default) [msgsplit@erinome ~]$ uberspace web log access status From 9ba4b3efff2a1f1e4d287e089d1522042bf088ae Mon Sep 17 00:00:00 2001 From: klml Date: Wed, 26 Jan 2022 22:22:25 +0100 Subject: [PATCH 04/36] alpine latest --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 3ee2f44..4a92864 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.10.1-alpine +FROM python:alpine WORKDIR /app COPY . /app From 9cd4591e0cebaf0c9e86da6c9e386419e72ef4ee Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Tue, 22 Mar 2022 18:00:44 +0100 Subject: [PATCH 05/36] privatebin.info --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2ba2135..2205130 100644 --- a/README.md +++ b/README.md @@ -91,11 +91,11 @@ access log is disabled ## better -There are better ways for real crypto: - +There are better ways: +* [privatebin.info](https://privatebin.info) is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. But [requires](https://github.com/PrivateBin/PrivateBin/blob/master/INSTALL.md#minimal-requirements) a database. * [openpgp.org](https://www.openpgp.org) ## Similar -* windmemo.com was a service to send messages you [could read only once](https://www.sebastian-kraus.com/windmemo-nur-der-erste-kann-es-lesen/). \ No newline at end of file +* windmemo.com was a service to send messages you [could read only once](https://www.sebastian-kraus.com/windmemo-nur-der-erste-kann-es-lesen/). From 73467fa51cee85c5cbaa074d623a2f1cf9a70ba1 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Thu, 11 May 2023 19:00:24 +0200 Subject: [PATCH 06/36] Create docker-image.yml --- .github/workflows/docker-image.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/docker-image.yml diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml new file mode 100644 index 0000000..eac633f --- /dev/null +++ b/.github/workflows/docker-image.yml @@ -0,0 +1,18 @@ +name: Docker Image CI + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Build the Docker image + run: docker build . --file Dockerfile --tag my-image-name:$(date +%s) From 7452b720f9f37869b581a944d306d365b71d67f8 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Thu, 11 May 2023 19:02:22 +0200 Subject: [PATCH 07/36] image name msgsplit --- .github/workflows/docker-image.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index eac633f..6adbe16 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -15,4 +15,4 @@ jobs: steps: - uses: actions/checkout@v3 - name: Build the Docker image - run: docker build . --file Dockerfile --tag my-image-name:$(date +%s) + run: docker build . --file Dockerfile --tag msgsplit:$(date +%s) From 8388b95a4b8d0542510cd5faa23a4e461930368b Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Mon, 15 May 2023 17:18:37 +0200 Subject: [PATCH 08/36] wording env --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2205130..ba0a917 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ message split allows you to send messages (passwords etc.) to another person wit * msgsplit encrypts the message with a [one-time-pad](https://en.wikipedia.org/wiki/One-time_pad) in Alices browser into a _ciphertext_ and _cryptographic-key_ * sends the _ciphertext_ to the server - * the server stores the _ciphertext_ in a key-value storage + * the server stores the _ciphertext_ in a prefixed environment variable. * returns the _storage-key_ to Alice * Alices browser creates a hyperlink with the _storage-key_ as URL-query (''?'') and the _cryptographic-key_ as URL-Fragment (''#'') * Alices sends this link via email or messenger to Bob From e7561ad65c6d488fe94614f54c2040f5abc74194 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Mon, 15 May 2023 17:19:04 +0200 Subject: [PATCH 09/36] rm actions --- .github/workflows/docker-image.yml | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 .github/workflows/docker-image.yml diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml deleted file mode 100644 index 6adbe16..0000000 --- a/.github/workflows/docker-image.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Docker Image CI - -on: - push: - branches: [ "master" ] - pull_request: - branches: [ "master" ] - -jobs: - - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - name: Build the Docker image - run: docker build . --file Dockerfile --tag msgsplit:$(date +%s) From bd6769e93d91f8fa22e77cbd608ba41cf0cf8b27 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Mon, 15 May 2023 17:53:10 +0200 Subject: [PATCH 10/36] golang --- .gitignore | 96 +--------------------------------------------- Dockerfile | 13 +++++-- README.md | 10 +++-- index.html | 2 +- msgsplit.go | 70 +++++++++++++++++++++++++++++++++ msgsplit.py | 63 ------------------------------ static/msgsplit.js | 14 ++++--- 7 files changed, 97 insertions(+), 171 deletions(-) create mode 100644 msgsplit.go delete mode 100644 msgsplit.py diff --git a/.gitignore b/.gitignore index 894a44c..bb20b59 100644 --- a/.gitignore +++ b/.gitignore @@ -1,85 +1,5 @@ # Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -.hypothesis/ -.pytest_cache/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# pyenv -.python-version - -# celery beat schedule file -celerybeat-schedule - -# SageMath parsed files -*.sage.py +msgsplit # Environments .env @@ -88,17 +8,3 @@ env/ venv/ ENV/ env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ diff --git a/Dockerfile b/Dockerfile index 4a92864..3bbd057 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,14 @@ -FROM python:alpine +FROM docker.io/library/golang:1.19-alpine AS builder-env +WORKDIR /app +COPY ./index.html /app +COPY ./msgsplit.go /app +COPY ./static /app/static +RUN CGO_ENABLED=0 go build ./msgsplit.go +RUN rm ./msgsplit.go +FROM scratch WORKDIR /app -COPY . /app +COPY --from=builder-env /app/ /app/ EXPOSE 8080 -CMD [ "python3", "msgsplit.py" ] +CMD [ "./msgsplit" ] diff --git a/README.md b/README.md index ba0a917..bf5614a 100644 --- a/README.md +++ b/README.md @@ -73,16 +73,18 @@ Working demo, you can use it, but there is no safety guarantee! Hostet on [uberspace.de](https://uberspace.de) with [supervisord](https://manual.uberspace.de/daemons-supervisord.html) `msgsplit.py` as [web backend](https://manual.uberspace.de/web-backends.html), static files (index.html, css, js) as default apache and [access log is disabled](https://manual.uberspace.de/web-logs). ``` + [msgsplit@erinome ~]$ cat ~/etc/services.d/msgsplit.ini [program:msgsplit] -command=python3 /home/msgsplit/msgsplit/msgsplit.py +command=/home/msgsplit/msgsplit/msgsplit autostart=yes autorestart=yes +# `startsecs` is set by Uberspace monitoring team, to prevent a broken service from looping +startsecs=30 [msgsplit@erinome ~]$ supervisorctl status -msgsplit RUNNING pid 17680, uptime 1:33:05 +msgsplit RUNNING pid 7138, uptime 0:09:34 [msgsplit@erinome ~]$ uberspace web backend list -/writeserver http:8080 => OK, listening: PID 17680, python3 /home/msgsplit/msgsplit/msgsplit.py -/readserver http:8080 => OK, listening: PID 17680, python3 /home/msgsplit/msgsplit/msgsplit.py +/writeread http:8080 => OK, listening: PID 7138, /home/msgsplit/msgsplit/msgsplit / apache (default) [msgsplit@erinome ~]$ uberspace web log access status diff --git a/index.html b/index.html index cd52d25..b8baf23 100644 --- a/index.html +++ b/index.html @@ -6,7 +6,7 @@ message split - +
diff --git a/msgsplit.go b/msgsplit.go new file mode 100644 index 0000000..094bdda --- /dev/null +++ b/msgsplit.go @@ -0,0 +1,70 @@ +package main + +import ( + "fmt" + "os" + "net/http" + crypto_rand "crypto/rand" + "encoding/binary" + math_rand "math/rand" +) + +// seed rand +// wanted to use https://github.com/google/uuid , but modules are a bigger thread +// from https://stackoverflow.com/a/54491783/2248997 +func init() { + var b [8]byte + _, err := crypto_rand.Read(b[:]) + if err != nil { + panic("cannot seed math/rand package with cryptographically secure random number generator") + } + math_rand.Seed(int64(binary.LittleEndian.Uint64(b[:]))) +} + +func main() { + // this is a wedged CRUD + // Create a env (max 256) + // Read AND Delete + // no Update + + http.HandleFunc("/writeread", func(w http.ResponseWriter, r *http.Request) { + // prefix ENV prevent reading system ENVs + storage_key := "msgsplit_" + r.ParseForm() + + // stores _ciphertext_ on the server in env + if cipher, found := r.Form["cipher"]; found { + + if len(cipher[0]) > 256 { + http.Error(w, "Payload Too Large", 413) + } + storage_rand := fmt.Sprintf("%d", math_rand.Int()) // example: 6334824724549167320 + storage_key += storage_rand // example: msgsplit_6334824724549167320 + os.Setenv(storage_key, cipher[0]) + + fmt.Fprintf(w, storage_rand) // example: 6334824724549167320 + // server reads the _ciphertext_ + } else if key, found := r.Form["key"]; found { + storage_key += key[0] // example: msgsplit_6334824724549167320 + cipher, cipher_exists := os.LookupEnv(storage_key) + if !cipher_exists { + http.Error(w, "Not Found", 404) + } + // delete cipher + os.Unsetenv(storage_key) // example: msgsplit_6334824724549167320 + fmt.Fprintf(w, cipher) + } else { + http.Error(w, "Not Found", 404) + } + }) + + http.Handle("/", http.FileServer(http.Dir("./"))) + + + httpPort, Port_exist := os.LookupEnv("PORT") + if !Port_exist { + httpPort = "8080" + } + fmt.Println("Start msgsplit server at port " + httpPort) + http.ListenAndServe(":" + httpPort, nil) +} diff --git a/msgsplit.py b/msgsplit.py deleted file mode 100644 index f92e345..0000000 --- a/msgsplit.py +++ /dev/null @@ -1,63 +0,0 @@ -import sys, os, random, http.server, socketserver - -# python3 msgsplit.py 80 -try: - PORT = int(sys.argv[1]) -except: - PORT = 8080 - -env_prefix = 'msgsplit_' - -class write_read(http.server.SimpleHTTPRequestHandler): - ## this is a wedged CRUD - ## Create a env (max 256) - ## Read AND Delete - ## no Update - - def _set_headers(self,content_length_response): - self.send_response(200) - self.send_header('Content-type', 'text/html') - self.send_header('Strict-Transport-Security', 'max-age=31536000') - self.send_header('Content-Security-Policy', "script-src 'self'") - self.send_header('Content-Length', content_length_response) - self.end_headers() - - def do_POST(self): - try : - content_length = int(self.headers['Content-Length']) - post_body = str(self.rfile.read(content_length).decode('utf-8')) - - ## stores _ciphertext_ on the server in a key-value storage - if self.path == "/writeserver" : - if (content_length > 256 ): - self.send_error(413) # 413 Payload Too Large - return - storage_key = str( random.randrange(1000, 1000000000000, 1) ) - os.environ[ env_prefix + storage_key ] = post_body - - self._set_headers(len(storage_key)) - self.wfile.write(storage_key.encode("utf-8")) ## to Alice - return - - ## server reads the _ciphertext_ - ## TODO with GET https://github.com/klml/msgsplit/issues/11 - if self.path == "/readserver" : - env_prefix_storage_key = env_prefix + post_body - ## server reads the ciphertext - ciphertext = os.environ[ env_prefix_storage_key ] - # overwrite env, just to be sure - os.environ[ env_prefix_storage_key ] = '' - # delete the _ciphertext_ - os.environ.pop( env_prefix_storage_key ) - - self._set_headers(len(ciphertext)) - self.wfile.write(ciphertext.encode("utf-8")) # to Bobs Browser - return - except: - self.send_error(404) # 404 Not Found - return - - -with socketserver.TCPServer(("", PORT), write_read) as httpd: - print("Http Server Serving at port", PORT) - httpd.serve_forever() \ No newline at end of file diff --git a/static/msgsplit.js b/static/msgsplit.js index c2f7879..400a29f 100644 --- a/static/msgsplit.js +++ b/static/msgsplit.js @@ -21,8 +21,12 @@ function de_en_crypt ( message, cryptographic_key ) { // send ciphertext or storage_key and get back cipherfile or encrypted message -function write_read_server( write_read_server_path , callbackFunction, post_data , cryptographic_key ) { - fetch( write_read_server_path, { method: "POST", body: post_data } ).then( +function write_read_server( cipher_key , callbackFunction, post_data , cryptographic_key ) { + + var data = new URLSearchParams(); + data.append(cipher_key, post_data); + + fetch( "writeread", { method: "POST", body: data } ).then( function(response) { if (response.status !== 200) { console.log('ERROR Status Code: ' + response.status); @@ -83,7 +87,7 @@ function create_plaintext2ciphertext() { // send proper characters to server var ciphertext_base64 = window.btoa( ciphertext ); - write_read_server( 'writeserver', make_linktobob, ciphertext_base64, cryptographic_key ); + write_read_server( 'cipher', make_linktobob, ciphertext_base64, cryptographic_key ); document.getElementById('sendmessage').style.opacity = 1.0; document.getElementById('setmessage' ).style.opacity = 0.8; @@ -92,7 +96,7 @@ function create_plaintext2ciphertext() { function get_ciphertext2plaintext() { // remove ? from window.location.search var storage_key = decodeURIComponent(window.location.search).substring(1) ; - write_read_server( 'readserver' , decrypt, storage_key ); + write_read_server( 'key', decrypt, storage_key ); document.getElementById('getmessagebtn').disabled = true ; } @@ -104,4 +108,4 @@ window.onload = function() { document.getElementById('sendmessage').style.display = 'none'; document.getElementById('getmessage' ).style.display = 'block'; } -}; \ No newline at end of file +}; From 24f490dbe23b8235c08b041620f68999497aac9f Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Wed, 17 May 2023 19:12:09 +0200 Subject: [PATCH 11/36] rm python --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index bf5614a..464235d 100644 --- a/README.md +++ b/README.md @@ -48,16 +48,16 @@ Do not use msgsplit for current used passwords. If the hyperlink gets stolen, this message is disclosed. -## tech stack +## install -msgsplit uses no dependencies (like [web.py](https://webpy.org/) oder bottle) -But plain [http.server](https://docs.python.org/3/library/http.server.html). - - -run with: +Build +``` +go build ./msgsplit.go +``` +Run ``` -python3 msgsplit.py +./msgsplit.go ``` Alternative: From 5dcb8f8ca647324de25998e8cbbedd0b3749ec86 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Thu, 18 May 2023 20:59:27 +0200 Subject: [PATCH 12/36] no py --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 464235d..2505fdd 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ Working demo, you can use it, but there is no safety guarantee! [msgsplit.klml.de](https://msgsplit.klml.de) -Hostet on [uberspace.de](https://uberspace.de) with [supervisord](https://manual.uberspace.de/daemons-supervisord.html) `msgsplit.py` as [web backend](https://manual.uberspace.de/web-backends.html), static files (index.html, css, js) as default apache and [access log is disabled](https://manual.uberspace.de/web-logs). +Hostet on [uberspace.de](https://uberspace.de) with [supervisord](https://manual.uberspace.de/daemons-supervisord.html) as [web backend](https://manual.uberspace.de/web-backends.html), static files (index.html, css, js) as default apache and [access log is disabled](https://manual.uberspace.de/web-logs). ``` From 574d150b770cc661464bf40f786f1e002f0f3888 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Thu, 18 May 2023 21:04:56 +0200 Subject: [PATCH 13/36] no py --- .dockerignore | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/.dockerignore b/.dockerignore index cf3a2bd..815d17c 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,14 +6,4 @@ Dockerfile .dockerignore -# Byte-compiled / optimized / DLL files -__pycache__/ -*/__pycache__/ -*/*/__pycache__/ -*/*/*/__pycache__/ -*.py[cod] -*/*.py[cod] -*/*/*.py[cod] -*/*/*/*.py[cod] - -README.md \ No newline at end of file +README.md From a5af7691898c5dbc369e9098e3f585ba8616f0b5 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Thu, 18 May 2023 21:05:09 +0200 Subject: [PATCH 14/36] rm redunancy --- Dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 3bbd057..4e49905 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,7 @@ FROM docker.io/library/golang:1.19-alpine AS builder-env WORKDIR /app -COPY ./index.html /app +COPY ./ /app COPY ./msgsplit.go /app -COPY ./static /app/static RUN CGO_ENABLED=0 go build ./msgsplit.go RUN rm ./msgsplit.go From d47391596cc77f8b428d9851bea9d3a38adfc9c3 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Thu, 18 May 2023 21:12:02 +0200 Subject: [PATCH 15/36] rm redunancy II --- Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 4e49905..3e27fdd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,6 @@ FROM docker.io/library/golang:1.19-alpine AS builder-env WORKDIR /app COPY ./ /app -COPY ./msgsplit.go /app RUN CGO_ENABLED=0 go build ./msgsplit.go RUN rm ./msgsplit.go From 27952cfa126360249851a63318d1236332e73111 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Thu, 25 May 2023 22:09:19 +0200 Subject: [PATCH 16/36] fix new param --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2505fdd..a28798c 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ There are several __security concerns__: * if ciphers don't get deleted and the offender gets your mail, your message is disclosed * The browser [generates](https://github.com/klml/msgsplit/blob/master/static/msgsplit.js#L5) the key for the message, if your browsers [Math.random](https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Math/math.random) is compromised, everything is worthless. * Only the transmitted message is encrypted. The receiver is not authenticated. The first one who receives the link, has the message. -* brutforce all ciphertexts (`for i in {1..99999999999} ; do curl -s -X POST http://msg.exmple.net:8080/writeread --form "storage_key=$1" ; done ;`): a ciphertext is still useless without the cryptographic-key. +* brutforce all ciphertexts (`for i in {1..99999999999} ; do curl -s -X POST http://msg.exmple.net:8080/writeread --form "key=$1" ; done ;`): a ciphertext is still useless without the cryptographic-key. ## persistent storage From b717212da69a5762071579170aad48b1b1518ee7 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Thu, 25 May 2023 22:13:23 +0200 Subject: [PATCH 17/36] enforce POST, read cipher deletes cipher first, so this is a change #11 --- msgsplit.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/msgsplit.go b/msgsplit.go index 094bdda..05f2f32 100644 --- a/msgsplit.go +++ b/msgsplit.go @@ -28,6 +28,11 @@ func main() { // no Update http.HandleFunc("/writeread", func(w http.ResponseWriter, r *http.Request) { + if r.Method != "POST" { + w.Header().Set("Allow", "POST") + http.Error(w, "Method Not Allowed", 405) + return + } // prefix ENV prevent reading system ENVs storage_key := "msgsplit_" r.ParseForm() From 2d2c764faf4b620403643609c641b63cff357dd1 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Thu, 25 May 2023 22:13:41 +0200 Subject: [PATCH 18/36] http status 410 gone --- msgsplit.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msgsplit.go b/msgsplit.go index 05f2f32..6004379 100644 --- a/msgsplit.go +++ b/msgsplit.go @@ -53,7 +53,7 @@ func main() { storage_key += key[0] // example: msgsplit_6334824724549167320 cipher, cipher_exists := os.LookupEnv(storage_key) if !cipher_exists { - http.Error(w, "Not Found", 404) + http.Error(w, "Gone", 410) } // delete cipher os.Unsetenv(storage_key) // example: msgsplit_6334824724549167320 From 3eeb1cf4e586c619e7dee17cacfbe4bbb7db0e06 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Thu, 25 May 2023 22:14:46 +0200 Subject: [PATCH 19/36] version bump --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index b8baf23..be2be57 100644 --- a/index.html +++ b/index.html @@ -6,7 +6,7 @@ message split - +
From f459c1a2c28d1810e4ef9bd4ee10297b0a4b19d5 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Thu, 25 May 2023 22:20:33 +0200 Subject: [PATCH 20/36] 1.20-alpine --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 3e27fdd..75930bc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/library/golang:1.19-alpine AS builder-env +FROM docker.io/library/golang:1.20-alpine AS builder-env WORKDIR /app COPY ./ /app RUN CGO_ENABLED=0 go build ./msgsplit.go From a354cfcdd912da5b5a3fbb210f499acfc6982b00 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Sat, 16 Dec 2023 13:12:42 +0100 Subject: [PATCH 21/36] FROM alpine --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 75930bc..412f6db 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/library/golang:1.20-alpine AS builder-env +FROM docker.io/library/golang:alpine AS builder-env WORKDIR /app COPY ./ /app RUN CGO_ENABLED=0 go build ./msgsplit.go From 75a4d2ffcc6f7ec2315de02f0b3d51d2b076a715 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Sat, 16 Dec 2023 13:17:26 +0100 Subject: [PATCH 22/36] Create docker-publish.yml --- .github/workflows/docker-publish.yml | 98 ++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 .github/workflows/docker-publish.yml diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..d397020 --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,98 @@ +name: Docker + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +on: + schedule: + - cron: '17 17 * * 5' + push: + branches: [ "master" ] + # Publish semver tags as releases. + tags: [ 'v*.*.*' ] + pull_request: + branches: [ "master" ] + +env: + # Use docker.io for Docker Hub if empty + REGISTRY: ghcr.io + # github.repository as / + IMAGE_NAME: ${{ github.repository }} + + +jobs: + build: + + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + # This is used to complete the identity challenge + # with sigstore/fulcio when running outside of PRs. + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Install the cosign tool except on PR + # https://github.com/sigstore/cosign-installer + - name: Install cosign + if: github.event_name != 'pull_request' + uses: sigstore/cosign-installer@6e04d228eb30da1757ee4e1dd75a0ec73a653e06 #v3.1.1 + with: + cosign-release: 'v2.1.1' + + # Set up BuildKit Docker container builder to be able to build + # multi-platform images and export cache + # https://github.com/docker/setup-buildx-action + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 + + # Login against a Docker registry except on PR + # https://github.com/docker/login-action + - name: Log into registry ${{ env.REGISTRY }} + if: github.event_name != 'pull_request' + uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + # Build and push Docker image with Buildx (don't push on PR) + # https://github.com/docker/build-push-action + - name: Build and push Docker image + id: build-and-push + uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0 + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + # Sign the resulting Docker image digest except on PRs. + # This will only write to the public Rekor transparency log when the Docker + # repository is public to avoid leaking data. If you would like to publish + # transparency data even for private images, pass --force to cosign below. + # https://github.com/sigstore/cosign + - name: Sign the published Docker image + if: ${{ github.event_name != 'pull_request' }} + env: + # https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable + TAGS: ${{ steps.meta.outputs.tags }} + DIGEST: ${{ steps.build-and-push.outputs.digest }} + # This step uses the identity token to provision an ephemeral certificate + # against the sigstore community Fulcio instance. + run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST} From 42a028e5ff46433add3612a8dfe14056905f8117 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Sat, 16 Dec 2023 13:29:05 +0100 Subject: [PATCH 23/36] rename branch main --- .github/workflows/docker-publish.yml | 4 ++-- README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index d397020..fd59dad 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -9,11 +9,11 @@ on: schedule: - cron: '17 17 * * 5' push: - branches: [ "master" ] + branches: [ "main" ] # Publish semver tags as releases. tags: [ 'v*.*.*' ] pull_request: - branches: [ "master" ] + branches: [ "main" ] env: # Use docker.io for Docker Hub if empty diff --git a/README.md b/README.md index a28798c..2220311 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ There are several __security concerns__: * If the server is compromised: * the stored cipher is useless, but you could manipulate the javascript. * if ciphers don't get deleted and the offender gets your mail, your message is disclosed -* The browser [generates](https://github.com/klml/msgsplit/blob/master/static/msgsplit.js#L5) the key for the message, if your browsers [Math.random](https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Math/math.random) is compromised, everything is worthless. +* The browser [generates](https://github.com/klml/msgsplit/blob/main/static/msgsplit.js#L5) the key for the message, if your browsers [Math.random](https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Math/math.random) is compromised, everything is worthless. * Only the transmitted message is encrypted. The receiver is not authenticated. The first one who receives the link, has the message. * brutforce all ciphertexts (`for i in {1..99999999999} ; do curl -s -X POST http://msg.exmple.net:8080/writeread --form "key=$1" ; done ;`): a ciphertext is still useless without the cryptographic-key. From c99395c5a2874c76934cae099aa82a1b26c53128 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Sat, 16 Dec 2023 13:33:35 +0100 Subject: [PATCH 24/36] ghcr.io/klml/msgsplit:main --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2220311..610e9a7 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ Run ``` Alternative: -Use plain image [klml/msgsplit](https://hub.docker.com/r/klml/msgsplit) or with [msgsplit-kubernetes](https://github.com/klml/msgsplit-kubernetes). +Use plain image `ghcr.io/klml/msgsplit:main` or with [msgsplit-kubernetes](https://github.com/klml/msgsplit-kubernetes). ## demo From 5ee18a861344c3081ecbb42174ee56372c3410b7 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Sat, 16 Dec 2023 13:43:56 +0100 Subject: [PATCH 25/36] version bump --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index be2be57..a83ff2c 100644 --- a/index.html +++ b/index.html @@ -6,7 +6,7 @@ message split - +
From f77b6750ee4e6a20ca703847e259e89f9bbb74d1 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Sat, 16 Dec 2023 13:59:44 +0100 Subject: [PATCH 26/36] CGO_ENABLED=0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 610e9a7..1a450ae 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ If the hyperlink gets stolen, this message is disclosed. Build ``` -go build ./msgsplit.go +CGO_ENABLED=0 go build ./msgsplit.go ``` Run From 50e4642213ccc42a0a2f06e205575aee7279cd57 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Fri, 22 Mar 2024 19:42:22 +0100 Subject: [PATCH 27/36] actions/checkout@main --- .github/workflows/docker-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index fd59dad..8c883ef 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -35,7 +35,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@main # Install the cosign tool except on PR # https://github.com/sigstore/cosign-installer From 0952c8228d2a07a48d1591a86a9418cc1ee41f5c Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Fri, 5 Apr 2024 20:02:32 +0200 Subject: [PATCH 28/36] typo --- msgsplit.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msgsplit.go b/msgsplit.go index 6004379..974eb31 100644 --- a/msgsplit.go +++ b/msgsplit.go @@ -10,7 +10,7 @@ import ( ) // seed rand -// wanted to use https://github.com/google/uuid , but modules are a bigger thread +// wanted to use https://github.com/google/uuid , but modules are a bigger threat // from https://stackoverflow.com/a/54491783/2248997 func init() { var b [8]byte From 36862d3b8c794b09b101717988a548e097c808ae Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Fri, 5 Apr 2024 20:35:20 +0200 Subject: [PATCH 29/36] heading build run --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1a450ae..9e7af87 100644 --- a/README.md +++ b/README.md @@ -48,14 +48,13 @@ Do not use msgsplit for current used passwords. If the hyperlink gets stolen, this message is disclosed. -## install +## Build -Build ``` CGO_ENABLED=0 go build ./msgsplit.go ``` -Run +## Run ``` ./msgsplit.go ``` From 76a8e3b133bef07ff6a0909cb5b74a6e3d382483 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Fri, 5 Apr 2024 20:59:52 +0200 Subject: [PATCH 30/36] As of Go 1.20 there is no reason to call Seed with a random value https://pkg.go.dev/math/rand --- README.md | 3 +++ index.html | 2 +- msgsplit.go | 13 ------------- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 9e7af87..4a08e9f 100644 --- a/README.md +++ b/README.md @@ -50,11 +50,14 @@ If the hyperlink gets stolen, this message is disclosed. ## Build +golang>1.20 is required + ``` CGO_ENABLED=0 go build ./msgsplit.go ``` ## Run + ``` ./msgsplit.go ``` diff --git a/index.html b/index.html index a83ff2c..415f15e 100644 --- a/index.html +++ b/index.html @@ -6,7 +6,7 @@ message split - +
diff --git a/msgsplit.go b/msgsplit.go index 974eb31..5bbfe45 100644 --- a/msgsplit.go +++ b/msgsplit.go @@ -4,22 +4,9 @@ import ( "fmt" "os" "net/http" - crypto_rand "crypto/rand" - "encoding/binary" math_rand "math/rand" ) -// seed rand -// wanted to use https://github.com/google/uuid , but modules are a bigger threat -// from https://stackoverflow.com/a/54491783/2248997 -func init() { - var b [8]byte - _, err := crypto_rand.Read(b[:]) - if err != nil { - panic("cannot seed math/rand package with cryptographically secure random number generator") - } - math_rand.Seed(int64(binary.LittleEndian.Uint64(b[:]))) -} func main() { // this is a wedged CRUD From e548cfc424cc890370904c32c14e39d6655f28e1 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Thu, 11 Apr 2024 10:25:52 +0200 Subject: [PATCH 31/36] cosign-release is optional, version bump --- .github/workflows/docker-publish.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 8c883ef..f95dd54 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -41,9 +41,7 @@ jobs: # https://github.com/sigstore/cosign-installer - name: Install cosign if: github.event_name != 'pull_request' - uses: sigstore/cosign-installer@6e04d228eb30da1757ee4e1dd75a0ec73a653e06 #v3.1.1 - with: - cosign-release: 'v2.1.1' + uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # v3.5.0 # Set up BuildKit Docker container builder to be able to build # multi-platform images and export cache From 3ac99856e87fd8fddbad81cc904a9ebeeb91e41d Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Sun, 14 Apr 2024 17:44:07 +0200 Subject: [PATCH 32/36] verbose --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a08e9f..4df27df 100644 --- a/README.md +++ b/README.md @@ -96,8 +96,9 @@ access log is disabled ## better There are better ways: + * [privatebin.info](https://privatebin.info) is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. But [requires](https://github.com/PrivateBin/PrivateBin/blob/master/INSTALL.md#minimal-requirements) a database. -* [openpgp.org](https://www.openpgp.org) +* and always [openpgp.org](https://www.openpgp.org) ## Similar From e4cf48143cadddefc42804283c63b8b756380af9 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Sun, 14 Apr 2024 17:47:24 +0200 Subject: [PATCH 33/36] pwpush.com --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4df27df..6aeccb4 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,7 @@ access log is disabled There are better ways: +* [pwpush.com](https://pwpush.com/) Passwords automatically expire after a certain number of views and/or time has passed. Track who, what and when. But more complex. * [privatebin.info](https://privatebin.info) is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. But [requires](https://github.com/PrivateBin/PrivateBin/blob/master/INSTALL.md#minimal-requirements) a database. * and always [openpgp.org](https://www.openpgp.org) From 051252345dbd50c1270ff3a2321b87ef4f9e394f Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Sun, 14 Apr 2024 20:29:52 +0200 Subject: [PATCH 34/36] comments verbose --- msgsplit.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/msgsplit.go b/msgsplit.go index 5bbfe45..8d77749 100644 --- a/msgsplit.go +++ b/msgsplit.go @@ -9,9 +9,9 @@ import ( func main() { - // this is a wedged CRUD - // Create a env (max 256) - // Read AND Delete + // this is a downscaled CRUD service + // Create a environment variable (max 256) for cipher + // Read AND Delete cipher // no Update http.HandleFunc("/writeread", func(w http.ResponseWriter, r *http.Request) { @@ -20,7 +20,7 @@ func main() { http.Error(w, "Method Not Allowed", 405) return } - // prefix ENV prevent reading system ENVs + // prefix environment variable, to prevent reading all system environment variables storage_key := "msgsplit_" r.ParseForm() @@ -30,6 +30,7 @@ func main() { if len(cipher[0]) > 256 { http.Error(w, "Payload Too Large", 413) } + // create unique identifier name for environment variable storage_rand := fmt.Sprintf("%d", math_rand.Int()) // example: 6334824724549167320 storage_key += storage_rand // example: msgsplit_6334824724549167320 os.Setenv(storage_key, cipher[0]) From c18fed5ba206885ebbedc97f59e4e558e2150790 Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Sun, 15 Sep 2024 14:02:55 +0200 Subject: [PATCH 35/36] horuspass --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6aeccb4..75fe300 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,7 @@ access log is disabled There are better ways: +* [horuspass.com/send](https://horuspass.com/send) uses also a hash parameter, but depends on `workers.cloudflare.com`. * [pwpush.com](https://pwpush.com/) Passwords automatically expire after a certain number of views and/or time has passed. Track who, what and when. But more complex. * [privatebin.info](https://privatebin.info) is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. But [requires](https://github.com/PrivateBin/PrivateBin/blob/master/INSTALL.md#minimal-requirements) a database. * and always [openpgp.org](https://www.openpgp.org) From 878fad9b0f2dec3c7fede39e1e6af30297664abf Mon Sep 17 00:00:00 2001 From: Klaus Mueller Date: Sun, 15 Sep 2024 14:04:19 +0200 Subject: [PATCH 36/36] ots.private.coffee --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 75fe300..31986df 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,8 @@ access log is disabled There are better ways: -* [horuspass.com/send](https://horuspass.com/send) uses also a hash parameter, but depends on `workers.cloudflare.com`. +* [ots.private.coffee](https://ots.private.coffee/) uses also a hash parameter and an expiration date. +* [horuspass.com/send](https://horuspass.com/send) uses also a hash parameter, an expiration date, but depends on `workers.cloudflare.com`. * [pwpush.com](https://pwpush.com/) Passwords automatically expire after a certain number of views and/or time has passed. Track who, what and when. But more complex. * [privatebin.info](https://privatebin.info) is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. But [requires](https://github.com/PrivateBin/PrivateBin/blob/master/INSTALL.md#minimal-requirements) a database. * and always [openpgp.org](https://www.openpgp.org)