added status bar, dryrun, force, stacking( enables to add mails later on). Added uuid module for safe, enhanced mail file parser

This commit is contained in:
2020-10-02 21:36:31 +02:00
parent f57960a4a6
commit 89df06bc77
5 changed files with 192 additions and 60 deletions

1
.gitignore vendored
View File

@@ -3,3 +3,4 @@
/node_modules
/config.json
/mails.txt
/out

View File

@@ -1,8 +1,9 @@
import * as fs from 'fs'
import { generateToken } from './src/generate'
import { SecureVault } from './src/vault'
import { exit } from 'process';
let configPath = "", action = -1, pubKey = "", privKey = "", safeFile = "", mails = "", html = "";
let configPath = "", action = -1, pubKey = "", privKey = "", safeFile = "", mails = "", html = "", dryrun = false, force = false;
// parse cli args
for (let i = 1; i < process.argv.length ; i++){
if (process.argv[i] === "--config"){
@@ -38,6 +39,8 @@ for (let i = 1; i < process.argv.length ; i++){
if (process.argv[i] === "--send"){ action = 1 }
if (process.argv[i] === "--decrypt"){ action = 2 }
if (process.argv[i] === "--genkey"){ action = 3 }
if (process.argv[i] === "--dryrun"){ dryrun = true }
if (process.argv[i] === "--force"){ force = true }
}
if ( action == -1){ throw new Error("No Action specified") }
if (!configPath && action == 1){ throw new Error("Config-Path not specified") }
@@ -54,17 +57,39 @@ if (action == 1){
// load config
const confRaw = fs.readFileSync(configPath, 'utf8')
let config:any = {}
let addition: boolean = false; // wenn nur weitere hinzugefügt werden
config = JSON.parse(confRaw)
// load safe if present
if (fs.existsSync(safeFile)){
dataSafe.loadData(safeFile);
config.usedTokens = dataSafe.getStorage(dataSafe.findStorage("usedTokens")[0].u);
config.usedMails = dataSafe.getStorage(dataSafe.findStorage("usedMails")[0].u);
addition = true;
}else{
config.usedTokens = [];
config.usedMails = [];
}
try {
config = JSON.parse(confRaw)
config.inFileMail = mails;
config.htmlPath = html;
config.dryrun = dryrun;
config.force = force;
} catch (error) {
console.error("Cannote read config file!")
process.exit(100);
}
generateToken(config,dataSafe).then(el => {
console.log(el)
dataSafe.saveData(safeFile);
if (addition){
dataSafe.setStorage(dataSafe.findStorage("usedTokens")[0].u,el.codes)
dataSafe.setStorage(dataSafe.findStorage("usedMails")[0].u,el.mails)
dataSafe.saveData(safeFile);
}else{
dataSafe.pushStorage('usedTokens',el.codes)
dataSafe.pushStorage('usedMails',el.mails)
dataSafe.saveData(safeFile);
}
}).catch(err => console.error("error", err))
}else if(action == 2){
let dataSafe: SecureVault = new SecureVault(pubKey,privKey);

67
package-lock.json generated
View File

@@ -1,9 +1,17 @@
{
"name": "random",
"name": "opentoken",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@types/cli-progress": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.8.0.tgz",
"integrity": "sha512-2OV7ybuYQc6ju6Xlg8ncQcPA/vVbMTSGS0vygjszi9O7swC63S6f2oAnP4CE+4ppRo7eCQovlj268KySt1MaUQ==",
"requires": {
"@types/node": "*"
}
},
"@types/handlebars": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@types/handlebars/-/handlebars-4.1.0.tgz",
@@ -25,11 +33,40 @@
"@types/node": "*"
}
},
"@types/uuid": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.0.tgz",
"integrity": "sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ=="
},
"ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
},
"cli-progress": {
"version": "3.8.2",
"resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.8.2.tgz",
"integrity": "sha512-qRwBxLldMSfxB+YGFgNRaj5vyyHe1yMpVeDL79c+7puGujdKJHQHydgqXDcrkvQgJ5U/d3lpf6vffSoVVUftVQ==",
"requires": {
"colors": "^1.1.2",
"string-width": "^4.2.0"
}
},
"colors": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
"integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA=="
},
"crypto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz",
"integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig=="
},
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"handlebars": {
"version": "4.7.6",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz",
@@ -42,6 +79,11 @@
"wordwrap": "^1.0.0"
}
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
@@ -62,12 +104,35 @@
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
},
"string-width": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.0"
}
},
"strip-ansi": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
"requires": {
"ansi-regex": "^5.0.0"
}
},
"uglify-js": {
"version": "3.10.4",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.4.tgz",
"integrity": "sha512-kBFT3U4Dcj4/pJ52vfjCSfyLyvG9VYYuGYPmrPvAxRw/i7xHiT4VvCev+uiEMcEEiu6UNB6KgWmGtSUYIWScbw==",
"optional": true
},
"uuid": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.0.tgz",
"integrity": "sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ=="
},
"wordwrap": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",

View File

@@ -10,19 +10,23 @@
"author": "",
"license": "ISC",
"dependencies": {
"@types/cli-progress": "^3.8.0",
"@types/handlebars": "^4.1.0",
"@types/node": "^14.11.1",
"@types/nodemailer": "^6.4.0",
"@types/uuid": "^8.3.0",
"cli-progress": "^3.8.2",
"crypto": "^1.0.1",
"handlebars": "^4.7.6",
"nodemailer": "^6.4.11"
"nodemailer": "^6.4.11",
"uuid": "^8.3.0"
},
"pkg": {
"scripts": "dist/**/*.js",
"targets": [
"node12"
],
"outputPath":"bin/"
"outputPath": "bin/"
},
"bin": "dist/index.js"
}

View File

@@ -1,73 +1,76 @@
import * as fs from 'fs'
import * as path from 'path'
import * as nodemailer from 'nodemailer';
import * as cliProgress from 'cli-progress'
import { shuffleArray } from './util/shuffle';
import { mkstring } from './util/token';
import * as Handlebars from "handlebars";
import Mail from 'nodemailer/lib/mailer';
import { SecureVault } from './vault';
import { parseMails } from './mailParser';
interface mail{
mail: string;
name: string;
}
export function generateToken(config: any,dataSafe: SecureVault): Promise<String[]>{
let pr = new Promise<String[]>((resolve,error) => {
let mailArray: mail[] = [];
export interface genReturn{
codes: string[];
mails: mail[];
}
// read and process mail list
let readline = require('readline'),
instream = fs.createReadStream(config.inFileMail),
outstream = new (require('stream'))(),
rl = readline.createInterface(instream, outstream);
rl.on('line', function (line:string) {
console.log(line);
mailArray.push({
mail: line.substr(0,line.indexOf(";")),
name: line.substr(line.indexOf(";") + 1)
})
});
rl.on('close', function (line:string) {
// next step
generateCodes(resolve,error,mailArray,config,dataSafe);
});
export function generateToken(config: any,dataSafe: SecureVault): Promise<genReturn>{
return new Promise<genReturn>((resolve,error) => {
parseMails(config).then(res => {
generateCodes(resolve,error,res,config,dataSafe);
})
});
return pr;
}
// generate codes
async function generateCodes(resolve: (value?: String[]) => void,error: (reason?: any) => void,mailArray: mail[],config: any,dataSafe: SecureVault){
async function generateCodes(resolve: (value?: genReturn) => void,error: (reason?: any) => void,mailArray: mail[],config: any,dataSafe: SecureVault){
console.log("\nGenerating codes")
const pbar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
pbar.start(mailArray.length, 0,{
speed: "N/A"
});
let position = 0;
let codeArray: string[] = [];
let checkString: string = '';
let listString: string = '';
for(let i = 0; i < mailArray.length; i++){ // as many codes as adresses
// check that codes are unique
let code = mkstring(4);
while (codeArray.includes(code)){
let code = '';
do{
code = mkstring(4);
}
}while ( (config.force ? codeArray : [...codeArray, ...config.usedTokens]).includes(code))
codeArray.push(code);
checkString = `${checkString}|${code}`
listString = `${listString}\n${code}`
position ++;
pbar.update(position);
}
checkString = checkString.substr(1);
listString = listString.substr(1);
pbar.stop();
//write code lists
try {
if (!fs.existsSync(path.dirname(config.outFileMatch))){
fs.mkdirSync(path.dirname(config.outFileMatch));
}
fs.writeFileSync(config.outFileMatch, checkString);
fs.writeFileSync(config.outFileCodes, listString);
} catch (error) {
error(error);
} catch (err) {
error(err);
}
sendMails(resolve,error,mailArray,codeArray,config,dataSafe);
}
// randomize mails and tokens
async function sendMails(resolve: (value?: String[]) => void,error: (reason?: any) => void,mailArray: mail[],codeArray: string[],config: any,dataSafe: SecureVault){
async function sendMails(resolve: (value?: genReturn) => void,error: (reason?: any) => void,mailArray: mail[],codeArray: string[],config: any,dataSafe: SecureVault){
let mailserver = nodemailer.createTransport(config.mail);
// read mail template
let template!: HandlebarsTemplateDelegate<any>;
@@ -79,36 +82,70 @@ async function sendMails(resolve: (value?: String[]) => void,error: (reason?: an
error(error);
}
console.log("\nSending mails")
const pbar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
pbar.start(mailArray.length, 0,{
speed: "N/A"
});
let position = 0;
shuffleArray(mailArray);
shuffleArray(codeArray);
if (config.force){dataSafe.clearVault();}
for(let i = 0; i < mailArray.length; i++){
// send mail
dataSafe.pushData({
name: mailArray[i].name,
mail: mailArray[i].mail,
code: codeArray[i]
})
if (!config.dryrun){
dataSafe.pushData({
name: mailArray[i].name,
mail: mailArray[i].mail,
code: codeArray[i]
})
}
await send(mailArray[i].name, mailArray[i].mail, codeArray[i],template,mailserver,config);
position ++;
pbar.update(position);
}
resolve(codeArray);
pbar.stop();
shuffleArray(mailArray);
shuffleArray(codeArray);
shuffleArray(mailArray);
shuffleArray(codeArray);
resolve({
codes: config.force ? codeArray : (config.dryrun ? config.usedTokens : [...codeArray, ...config.usedTokens]),
mails: config.force ? mailArray : (config.dryrun ? config.usedMails : [...mailArray, ...config.usedMails])
});
}
async function send(name: string, mail: string, code: string,template: HandlebarsTemplateDelegate<any>,mailserver: Mail,config: any){
// fill template
let html = template({
"name": name,
"mail": mail,
"code": code
})
let mailOptions = {
from: `${config.mailFrom} <${config.mail.auth.user}>`, // sender address
to: mail, // list of receivers
subject: `Dein Zugangscode zur BJR Wahl`, // Subject line
html: html
};
try {
await mailserver.sendMail(mailOptions);
} catch (error) {
console.log(`Error sendign mail to ${mail} : ${error}`)
if (config.dryrun){
await delay(100);
console.log(`\n\x1b[36m -> dryrun: would send to ${mail}\x1b[0m`);
}else{
// fill template
let html = template({
"name": name,
"mail": mail,
"code": code
})
let mailOptions = {
from: `${config.mailFrom} <${config.mail.auth.user}>`, // sender address
to: mail, // list of receivers
subject: `Dein Zugangscode zur BJR Wahl`, // Subject line
html: html
};
try {
await mailserver.sendMail(mailOptions);
} catch (error) {
console.log(`Error sendign mail to ${mail} : ${error}`)
}
}
}
function delay(t: number, val?: number) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(val);
}, t);
});
}