@@ -0,0 +1,118 @@ | |||
# Logs | |||
logs | |||
*.log | |||
npm-debug.log* | |||
yarn-debug.log* | |||
yarn-error.log* | |||
lerna-debug.log* | |||
.pnpm-debug.log* | |||
# Diagnostic reports (https://nodejs.org/api/report.html) | |||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json | |||
# Runtime data | |||
pids | |||
*.pid | |||
*.seed | |||
*.pid.lock | |||
# Directory for instrumented libs generated by jscoverage/JSCover | |||
lib-cov | |||
# Coverage directory used by tools like istanbul | |||
coverage | |||
*.lcov | |||
# nyc test coverage | |||
.nyc_output | |||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) | |||
.grunt | |||
# Bower dependency directory (https://bower.io/) | |||
bower_components | |||
# node-waf configuration | |||
.lock-wscript | |||
# Compiled binary addons (https://nodejs.org/api/addons.html) | |||
build/Release | |||
# Dependency directories | |||
node_modules/ | |||
jspm_packages/ | |||
# Snowpack dependency directory (https://snowpack.dev/) | |||
web_modules/ | |||
# TypeScript cache | |||
*.tsbuildinfo | |||
# Optional npm cache directory | |||
.npm | |||
# Optional eslint cache | |||
.eslintcache | |||
# Microbundle cache | |||
.rpt2_cache/ | |||
.rts2_cache_cjs/ | |||
.rts2_cache_es/ | |||
.rts2_cache_umd/ | |||
# Optional REPL history | |||
.node_repl_history | |||
# Output of 'npm pack' | |||
*.tgz | |||
# Yarn Integrity file | |||
.yarn-integrity | |||
# dotenv environment variables file | |||
.env | |||
.env.test | |||
.env.production | |||
# parcel-bundler cache (https://parceljs.org/) | |||
.cache | |||
.parcel-cache | |||
# Next.js build output | |||
.next | |||
out | |||
# Nuxt.js build / generate output | |||
.nuxt | |||
dist | |||
# Gatsby files | |||
.cache/ | |||
# Comment in the public line in if your project uses Gatsby and not Next.js | |||
# https://nextjs.org/blog/next-9-1#public-directory-support | |||
# public | |||
# vuepress build output | |||
.vuepress/dist | |||
# Serverless directories | |||
.serverless/ | |||
# FuseBox cache | |||
.fusebox/ | |||
# DynamoDB Local files | |||
.dynamodb/ | |||
# TernJS port file | |||
.tern-port | |||
# Stores VSCode versions used for testing VSCode extensions | |||
.vscode-test | |||
# yarn v2 | |||
.yarn/cache | |||
.yarn/unplugged | |||
.yarn/build-state.yml | |||
.yarn/install-state.gz | |||
.pnp.* |
@@ -0,0 +1,45 @@ | |||
var createError = require('http-errors'); | |||
var express = require('express'); | |||
var path = require('path'); | |||
var cookieParser = require('cookie-parser'); | |||
var logger = require('morgan'); | |||
var indexRouter = require('./routes/index'); | |||
var usersRouter = require('./routes/users'); | |||
var app = express(); | |||
require('dotenv').config() | |||
// view engine setup | |||
app.set('views', path.join(__dirname, 'views')); | |||
app.set('view engine', 'pug'); | |||
app.use(require('express-bulma')('/bulma.css')); | |||
app.use(express.json()); | |||
app.use(logger('dev')); | |||
app.use(express.json()); | |||
app.use(express.urlencoded({ extended: true })); | |||
app.use(cookieParser()); | |||
app.use(express.static(path.join(__dirname, 'public'))); | |||
app.use('/', indexRouter); | |||
// catch 404 and forward to error handler | |||
app.use(function(req, res, next) { | |||
next(createError(404)); | |||
}); | |||
// error handler | |||
app.use(function(err, req, res, next) { | |||
// set locals, only providing error in development | |||
res.locals.message = err.message; | |||
res.locals.error = req.app.get('env') === 'development' ? err : {}; | |||
// render the error page | |||
res.status(err.status || 500); | |||
res.render('error'); | |||
}); | |||
module.exports = app; |
@@ -0,0 +1,90 @@ | |||
#!/usr/bin/env node | |||
/** | |||
* Module dependencies. | |||
*/ | |||
var app = require('../app'); | |||
var debug = require('debug')('pseudomail:server'); | |||
var http = require('http'); | |||
/** | |||
* Get port from environment and store in Express. | |||
*/ | |||
var port = normalizePort(process.env.PORT || '3000'); | |||
app.set('port', port); | |||
/** | |||
* Create HTTP server. | |||
*/ | |||
var server = http.createServer(app); | |||
/** | |||
* Listen on provided port, on all network interfaces. | |||
*/ | |||
server.listen(port); | |||
server.on('error', onError); | |||
server.on('listening', onListening); | |||
/** | |||
* Normalize a port into a number, string, or false. | |||
*/ | |||
function normalizePort(val) { | |||
var port = parseInt(val, 10); | |||
if (isNaN(port)) { | |||
// named pipe | |||
return val; | |||
} | |||
if (port >= 0) { | |||
// port number | |||
return port; | |||
} | |||
return false; | |||
} | |||
/** | |||
* Event listener for HTTP server "error" event. | |||
*/ | |||
function onError(error) { | |||
if (error.syscall !== 'listen') { | |||
throw error; | |||
} | |||
var bind = typeof port === 'string' | |||
? 'Pipe ' + port | |||
: 'Port ' + port; | |||
// handle specific listen errors with friendly messages | |||
switch (error.code) { | |||
case 'EACCES': | |||
console.error(bind + ' requires elevated privileges'); | |||
process.exit(1); | |||
break; | |||
case 'EADDRINUSE': | |||
console.error(bind + ' is already in use'); | |||
process.exit(1); | |||
break; | |||
default: | |||
throw error; | |||
} | |||
} | |||
/** | |||
* Event listener for HTTP server "listening" event. | |||
*/ | |||
function onListening() { | |||
var addr = server.address(); | |||
var bind = typeof addr === 'string' | |||
? 'pipe ' + addr | |||
: 'port ' + addr.port; | |||
debug('Listening on ' + bind); | |||
} |
@@ -0,0 +1 @@ | |||
MIAB_AUTHORIZATIONHEADER=Basic da39a3ee5e6b4b0d3255bfef95601890afd80709 |
@@ -0,0 +1,24 @@ | |||
{ | |||
"name": "pseudomail", | |||
"version": "0.0.0", | |||
"private": true, | |||
"scripts": { | |||
"start": "node ./bin/www" | |||
}, | |||
"dependencies": { | |||
"cookie-parser": "~1.4.4", | |||
"debug": "~2.6.9", | |||
"dotenv": "^10.0.0", | |||
"express": "~4.16.1", | |||
"express-bulma": "^1.0.1", | |||
"got": "^11.8.2", | |||
"http-errors": "~1.6.3", | |||
"jade": "~1.11.0", | |||
"morgan": "~1.9.1", | |||
"pug": "^3.0.2", | |||
"usernames": "^1.0.0" | |||
}, | |||
"devDependencies": { | |||
"@fortawesome/fontawesome-free": "^5.15.4" | |||
} | |||
} |
@@ -0,0 +1,8 @@ | |||
body { | |||
padding: 50px; | |||
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; | |||
} | |||
a { | |||
color: #00B7FF; | |||
} |
@@ -0,0 +1,121 @@ | |||
var express = require('express'); | |||
var router = express.Router(); | |||
const got = require('got'); | |||
const usernames = require('usernames') | |||
const headers = { Authorization: process.env.MIAB_AUTHORIZATIONHEADER } | |||
// initialize the usernames library to generate random usernames | |||
const generate = usernames({ | |||
length: 8, | |||
separator: '.', | |||
patterns: [['adjectives', 'nouns'], ['adverbs', 'verbs']] | |||
}) | |||
// get home page | |||
router.get('/', function (req, res, next) { | |||
// supply a pregenerated username and render the page | |||
var generatedUsername = generate() | |||
res.render('index', { suggestedEmail: generatedUsername }); | |||
}); | |||
// post form sent | |||
router.post('/', function (req, res) { | |||
var got = require('got'); | |||
// get post body | |||
var redirectFrom = req.body.email | |||
var redirectTo = req.body.redirect_email | |||
var wantedDomain = req.body.domain | |||
// combine mailaddress and domain part | |||
var wantedMailCombined = redirectFrom + '@' + wantedDomain | |||
var status = '' | |||
var message = '' | |||
var qs = require('qs'); | |||
(async () => { | |||
// get all mail aliases currently configured on the target system | |||
var body = await got.get("https://box.beisel.it/admin/mail/aliases?format=json", { | |||
headers: headers}).json() | |||
// verify that the domain is in our list of allowed domains | |||
// FIXME that is actually not true - we're just verifying whether it is a configured domain for the systemm | |||
// take care - no don't - fix this!! | |||
var foundDomain = -1 | |||
for (var i = 0; i < body.length; i++) { | |||
if (wantedDomain == body[i].domain) { | |||
foundDomain = i | |||
} | |||
} | |||
if (foundDomain > -1) { | |||
// verify that the alias isn't currently in use | |||
// I should think about whether users can 'steal' their account names | |||
var foundAlias = -1 | |||
for (var i = 0; i < body[foundDomain].aliases.length; i++) { | |||
if (wantedMailCombined == body[foundDomain].aliases[i].address) { | |||
message += 'Fehler: Alias ( <strong>' + wantedMailCombined + '</strong> ) existiert bereits' | |||
status = 'error' | |||
foundAlias = i | |||
} | |||
} | |||
// If nothing bad has happened, the domain was found, the alias wasn't found and the | |||
// error variable hasn't otherwise been set to true I think nobody is exploiting anything | |||
// try and make a post request to the mailserver to upsert the alias | |||
if (foundDomain == -1 || foundAlias > -1 || status == 'error') { | |||
// if for any reason an error case has slipped through | |||
// but the status is unset set it correctly | |||
status = 'error' | |||
} else { | |||
var body = qs.stringify({ | |||
'update_if_exists': 1, | |||
'address': wantedMailCombined, | |||
'forwards_to': redirectTo | |||
}) | |||
try { | |||
// post request to mailserver | |||
var createAlias = await got.post("https://box.beisel.it/admin/mail/aliases/add", { | |||
headers: headers, | |||
form: { | |||
update_if_exists: 1, | |||
address: wantedMailCombined, | |||
forwards_to: redirectTo | |||
} | |||
}) | |||
} catch (error) { | |||
console.log(error.request) | |||
} | |||
// set the success message and status | |||
message = 'Alias erfolgreich angelegt!' | |||
status = 'success' | |||
} | |||
} else { | |||
// the domain was not found - cannot continue | |||
// set error status | |||
status = 'error' | |||
message = 'Fehler: Domain nicht gefunden' | |||
} | |||
// render the index template form again, but this time | |||
// pass the passed in parameters as default values | |||
// also pass the message in | |||
res.render('index', { | |||
suggestedEmail: redirectFrom, | |||
domain: wantedDomain, | |||
redirect_email: redirectTo, | |||
message: message, | |||
status: status | |||
}); | |||
})(); | |||
}); | |||
module.exports = router; |
@@ -0,0 +1,9 @@ | |||
var express = require('express'); | |||
var router = express.Router(); | |||
/* GET users listing. */ | |||
router.get('/', function(req, res, next) { | |||
res.send('respond with a resource'); | |||
}); | |||
module.exports = router; |
@@ -0,0 +1,10 @@ | |||
extends layout.pug | |||
block title | |||
title Fehler: #{error.status} #{message} | |||
block message | |||
| #[strong Fehler: ] | |||
= error.status + ' - ' + message | |||
pre(class='is-rounded') #{error.stack} | |||
@@ -0,0 +1,9 @@ | |||
extends layout.pug | |||
block body | |||
form(class='box') | |||
div(class='field') | |||
label(class='label') | |||
| Name | |||
div(class='control') | |||
input(class='input', type='text', placeholder='Text Input!!') |
@@ -0,0 +1,3 @@ | |||
extends layout | |||
foo |
@@ -0,0 +1,73 @@ | |||
extends layout.pug | |||
block body | |||
- var domains = ['hermann.ist', 'munchkins.io', 'aretheystillusing5blockchains.xyz', 'onv6.de', 'fuckyea.de', 'ipadr.de'] | |||
div(class='columns') | |||
// spacer | |||
div(class='column') | |||
// content | |||
div(class='column is-four-fifths') | |||
form(class='box' method='post' action='/') | |||
// wunschadresse | |||
div(class='field') | |||
// wunschadresse-label | |||
div(class='field-label is-normal') | |||
label(class='label') | |||
| Wunsch-Adresse | |||
// wunschadresse-body | |||
div(class='field-body') | |||
div(class='field has-addons') | |||
div(class='control is-expanded') | |||
input(class='input', type='text', name='email', value=suggestedEmail) | |||
div(class='control') | |||
a(class='button is-static') | |||
| @ | |||
div(class='control') | |||
div(class='select is-info') | |||
select(name='domain' value=domain) | |||
// if no domain has been passed in select the Domain value | |||
if !domain | |||
option(disabled='true' selected='selected') | |||
| Domain | |||
else | |||
option(disabled='true') | |||
| Domain | |||
// go through the domains in the list and add them to the | |||
// select - if one is passed in select that one | |||
each obj in domains | |||
if domain == obj | |||
option(value=obj, selected='selected') #{obj} | |||
else | |||
option(value=obj) #{obj} | |||
// Ziel-Adresse | |||
div(class='field') | |||
// ziel-adresse-label | |||
div(class='field-label is-normal ') | |||
label(class='label') | |||
| Ziel-Adresse | |||
// ziel-adresse-body | |||
div(class='field-body') | |||
div(class='field has-addons has-addons-right' ) | |||
div(class='control is-expanded') | |||
input(class='input', type='email', name='redirect_email', placeholder='eure.email@gmail.com' value=redirect_email) | |||
// button-group | |||
div(class='field is-grouped is-grouped-centered') | |||
p(class='control') | |||
button(class='button is-link is-primary') | |||
| Abschicken | |||
p(class='control') | |||
a(href='/' class='button is-link is-danger') Cancel | |||
// spacer | |||
div(class='column') | |||
block message | |||
| !{message} |
@@ -0,0 +1,39 @@ | |||
doctype html | |||
html | |||
head | |||
meta(charset='utf-8') | |||
meta(name='viewport' content='width=device-width, initial-scale=1') | |||
link(rel="stylesheet", href="//cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css") | |||
script(src='https://use.fontawesome.com/1560649591.js') | |||
block title | |||
title Weiterleitungs-Generator - #{title} | |||
body | |||
section(class='hero is-info' ) | |||
div(class='hero-body') | |||
p(class='title') | |||
a(href='/' class='is-link') Pacey's Wegwerf-Emails | |||
p(class='subtitle') | |||
| Muss ich da meine E-Mail Adresse angeben? | |||
if message | |||
section(class='section pt-2 mt-2 pb-0 mb-0') | |||
div(class='container ') | |||
if status == 'error' | |||
div(class='notification is-danger') | |||
block message | |||
else | |||
div(class='notification is-primary') | |||
block message | |||
section(class='section') | |||
div(class='container is-fluid') | |||
block body | |||
block footer | |||
footer(class='footer') | |||
div(class='content has-text-centered') | |||
p | |||
| Built with ❤️ by pacey |