Commit d3857dd0 authored by Sheogorath's avatar Sheogorath 🌍

Add PGPme project to my blog

This little project adds a site that everyone can use to encrypt a
message and send it to me using their email client.

This should simplify the sharing of messages and secret with me, without
the need of putting an entire OpenPGP infrastructure on the person's
side just to encrypt the message. It seems like a lot of people are
overwhelmed by that.

Since I don't want to run any active component to send emails on my side
and I don't want to add 3rd parties to handle that for me, simply
opening the message in the user's client seems the right thing to do.It
Also makes sure, that this has no GDPR implications since nothing can be
identified from my side. The user has to decide whenever they want to
send the email or not.
parent 5281669f
......@@ -16,7 +16,7 @@ spellcheck:
- npm i -g markdown-spellcheck
- mdspell -r -n -a --en-gb "_posts/*.md" "_posts/*.markdown"
- mdspell -r -n -a --en-gb "_posts/*.md" "_posts/*.markdown" ""
- docker
......@@ -150,6 +150,7 @@ October-Plattform
......@@ -22,7 +22,7 @@ server {
add_header X-Frame-Options "DENY";
add_header Referrer-Policy "no-referrer";
add_header Content-Security-Policy "default-src 'none'; script-src 'self'; img-src data: 'self'; style-src 'self' 'unsafe-inline'; font-src data: 'self'; object-src data:; base-uri 'none'; form-action 'none';";
add_header Content-Security-Policy "default-src 'none'; script-src 'self'; img-src data: 'self'; style-src 'self' 'unsafe-inline'; font-src data: 'self'; object-src data:; base-uri 'none'; form-action 'none'; worker-src 'self'; connect-src 'self'";
add_header Feature-Policy "geolocation 'none'; midi 'none'; notifications 'none'; push 'none'; sync-xhr 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope 'none'; speaker 'none'; vibrate 'none'; fullscreen 'self'; payment 'none'; usb 'none';";
add_header Allow "GET, HEAD" always;
\ No newline at end of file
......@@ -59,3 +59,18 @@ pre.highlight code,
border: 3px solid #fff;
.pgpme textarea {
width: 100%;
height: 20vh;
min-height: 18vh;
resize: vertical;
.pgpme .results {
display: none;
.pgpme form {
margin-bottom: 4vh;
This diff is collapsed.
This diff is collapsed.
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3.0 of the License, or (at your option) any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// Lesser General Public License for more details.
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
/* eslint-disable no-restricted-globals */
/* eslint-disable no-var */
/* eslint-disable vars-on-top */
* @fileoverview Provides functions for communicating with workers
* @see module:openpgp.initWorker
* @see module:openpgp.getWorker
* @see module:openpgp.destroyWorker
* @see module:worker/async_proxy
* @module worker/worker
self.window = self; // to make UMD bundles work
var openpgp = window.openpgp;
var randomQueue = [];
* Handle random buffer exhaustion by requesting more random bytes from the main window
* @returns {Promise<Object>} Empty promise whose resolution indicates that the buffer has been refilled
function randomCallback() {
if (!randomQueue.length) {
self.postMessage({ event: 'request-seed', amount: MAX_SIZE_RANDOM_BUFFER });
return new Promise(function(resolve) {
openpgp.crypto.random.randomBuffer.init(MAX_SIZE_RANDOM_BUFFER, randomCallback);
* Handle messages from the main window.
* @param {Object} event Contains event type and data
self.onmessage = function(event) {
var msg = || {};
switch (msg.event) {
case 'configure':
case 'seed-random':
var queueCopy = randomQueue;
randomQueue = [];
for (var i = 0; i < queueCopy.length; i++) {
delegate(, msg.event, msg.options || {});
* Set config from main context to worker context.
* @param {Object} config The openpgp configuration
function configure(config) {
Object.keys(config).forEach(function(key) {
openpgp.config[key] = config[key];
* Seed the library with entropy gathered window.crypto.getRandomValues
* as this api is only avalible in the main window.
* @param {ArrayBuffer} buffer Some random bytes
function seedRandom(buffer) {
if (!(buffer instanceof Uint8Array)) {
buffer = new Uint8Array(buffer);
* Generic proxy function that handles all commands from the public api.
* @param {String} method The public api function to be delegated to the worker thread
* @param {Object} options The api function's options
function delegate(id, method, options) {
if (typeof openpgp[method] !== 'function') {
response({ id:id, event:'method-return', err:'Unknown Worker Event' });
// construct ReadableStreams from MessagePorts
// parse cloned packets
options = openpgp.packet.clone.parseClonedPackets(options, method);
openpgp[method](options).then(function(data) {
// clone packets (for web worker structured cloning algorithm)
response({ id:id, event:'method-return', data:openpgp.packet.clone.clonePackets(data) });
}).catch(function(e) {
id:id, event:'method-return', err:e.message, stack:e.stack
* Respond to the main window.
* @param {Object} event Contains event type and data
function response(event) {
self.postMessage(event, openpgp.util.getTransferables(, true));
* Let the main window know the worker has loaded.
postMessage({ event: 'loaded' });
/*! OpenPGP.js v4.6.0 - 2019-08-12 - this is LGPL licensed code, see LICENSE/our website for more information. */
!function(){return function e(n,t,r){function o(a,f){if(!t[a]){if(!n[a]){var s="function"==typeof require&&require;if(!f&&s)return s(a,!0);if(i)return i(a,!0);var u=new Error("Cannot find module '"+a+"'");throw u.code="MODULE_NOT_FOUND",u}var c=t[a]={exports:{}};n[a][0].call(c.exports,function(e){return o(n[a][1][e]||e)},c,c.exports,e,n,t,r)}return t[a].exports}for(var i="function"==typeof require&&require,a=0;a<r.length;a++)o(r[a]);return o}}()({1:[function(e,n,t){self.window=self,importScripts("openpgp.min.js");var r=window.openpgp,o=[],i=6e4;function a(e){self.postMessage(e,r.util.getTransferables(,!0))}r.crypto.random.randomBuffer.init(i,function(){return o.length||self.postMessage({event:"request-seed",amount:i}),new Promise(function(e){o.push(e)})}),self.onmessage=function(e){var n,||{};switch(t.event){case"configure":n=t.config,Object.keys(n).forEach(function(e){r.config[e]=n[e]});break;case"seed-random":!function(e){e instanceof Uint8Array||(e=new Uint8Array(e));r.crypto.random.randomBuffer.set(e)}(t.buf);var i=o;o=[];for(var f=0;f<i.length;f++)i[f]();break;default:!function(e,n,t){if("function"!=typeof r[n])return void a({id:e,event:"method-return",err:"Unknown Worker Event"});r.util.restoreStreams(t),t=r.packet.clone.parseClonedPackets(t,n),r[n](t).then(function(n){a({id:e,event:"method-return",data:r.packet.clone.clonePackets(n)})}).catch(function(n){r.util.print_debug_error(n),a({id:e,event:"method-return",err:n.message,stack:n.stack})})}(,t.event,t.options||{})}},postMessage({event:"loaded"})},{}]},{},[1]);
\ No newline at end of file
layout: null
exclude: 'yes'
{% include jquery3.3.1.min.js %}
{% include openpgp.min.js %}
const openpgp = window.openpgp
openpgp.initWorker({ path:'/js/openpgp.worker.min.js' }) // set the relative web worker path
let pubkey = ""
$.get("/openpgp/0xFCB98C2A3EC6F601.txt", {} ,null, "text")
.done(data => {
pubkey = data
$( "#pgpme_form" ).submit(async function( event ) {
const text = $('#pgpme_textfield').val()
const publicKey = await openpgp.key.readArmored(pubkey)
const options = {
message: openpgp.message.fromText(text),
publicKeys: publicKey.keys
openpgp.encrypt(options).then(ciphertext => {
encrypted =
$(".pgpme .results").show()
.fail(error => {
$("#pgpme_mailto").click(() => {
const subject = encodeURIComponent("Encrypted email from PGPME")
const body = encodeURIComponent($("#pgpme_result").text())
window.location.href = `${subject}&body=${body}`;
layout: page
title: Send me OpenPGP messages
robots: noindex
script: pgpme
This page can be used to easily send me OpenPGP encrypted emails :)
1. Type the message you want to send me into the field below.
2. Click on "Encrypt message"
3. Either copy the result to your email app or click on "Open in mail app"
4. Send the email to `` or the email address that is pre-filled.
<div class="pgpme">
<form id="pgpme_form">
<textarea id="pgpme_textfield"></textarea>
<button type="submit">Encrypt message</button>
<div class="results">
<pre id="pgpme_result"></pre>
<button id="pgpme_mailto">Open in mail app</button>
*This page is using [OpenPGPjs](*
User-agent: *
Disallow: /impressum
Disallow: /pgpme
sitemap: /sitemap.xml
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment