Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b739f3d8b | |||
| 89df06bc77 | |||
| f57960a4a6 | |||
| 5899972233 | |||
| 469127c303 | |||
|
|
1517785d30 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,3 +3,4 @@
|
||||
/node_modules
|
||||
/config.json
|
||||
/mails.txt
|
||||
/out
|
||||
95
README.md
95
README.md
@@ -76,6 +76,7 @@ Dazu muss golgender Befehl ausgeführt werden:
|
||||
ts-node .\index.ts --privkey private.key --decrypt --safe .\out\credentials.json
|
||||
|
||||
## Config-Datei
|
||||
```
|
||||
{
|
||||
"mail":{
|
||||
"host": "<mailserver>",
|
||||
@@ -91,24 +92,102 @@ ts-node .\index.ts --privkey private.key --decrypt --safe .\out\credentials.json
|
||||
}
|
||||
},
|
||||
"mailFrom": "<absender name>",
|
||||
"outFileCodes": "<ausgabedatei codes>",
|
||||
"outFileMatch": "<ausgabedatei regex>"
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Syntax
|
||||
|
||||
==> Schlüsselpaar Erzeugen
|
||||
`ts-node .\index.ts --privkey <path-to-private-key> --pubkey <path-to-public-key> --genkey
|
||||
`ts-node .\index.ts --privkey <path-to-private-key> --pubkey <path-to-public-key> --genkey`
|
||||
|
||||
z.B. `ts-node .\index.ts --privkey private.key --pubkey public.key --genkey
|
||||
z.B. `ts-node .\index.ts --privkey private.key --pubkey public.key --genkey`
|
||||
|
||||
==> Codes Erzeugen und versenden
|
||||
`ts-node .\index.ts --config <path-to-config-key> --pubkey <path-to-public-key> --send --safe .\out\credentials.json --mails <path-to-mail-list> -html <path-to-html-template>
|
||||
`ts-node .\index.ts --config <path-to-config-key> --pubkey <path-to-public-key> --send --safe .\out\credentials.json --mails <path-to-mail-list> -html <path-to-html-template>`
|
||||
|
||||
z.B. `ts-node .\index.ts --config config.json --pubkey public.key --send --safe .\out\credentials.json --mails mail.txt -html template.html
|
||||
Achtung: Es wird im Safe geprüft, ob Mailadressen bereits "bedient" wurden. Sollte dies der Fall sein, werden keine Mails an diese Adresse gesendet. Dies lässt sich mit dem Schalter `--force` umgehen.
|
||||
|
||||
z.B. `ts-node .\index.ts --config config.json --pubkey public.key --send --safe .\out\credentials.json --mails mail.txt -html template.html`
|
||||
|
||||
==> Safe entschlüsseln
|
||||
`ts-node .\index.ts --privkey <path-to-private-key> --decrypt --safe .\out\credentials.json
|
||||
`ts-node .\index.ts --privkey <path-to-private-key> --decrypt --safe .\out\credentials.json`
|
||||
|
||||
z.B. `ts-node .\index.ts --privkey private.key --decrypt --safe .\out\credentials.json
|
||||
z.B. `ts-node .\index.ts --privkey private.key --decrypt --safe .\out\credentials.json`
|
||||
|
||||
### Erweiterte Schalter
|
||||
|
||||
- `--dryrun` : Mails werden nicht versendet und der Safe wird nicht verändert.
|
||||
- `--force` : Alle Codes werden neu generiert und alle mails werden gesendet. Ignoriere bereits gesendete mails.
|
||||
|
||||
## Gepackte Binaries
|
||||
Die gepackten Binaries sind für Linux, MacOS und Windoof verfügbar: [Binaries](https://gitlab.dennisgunia.de/dennisgunia/one-time-code-js/-/tree/master/bin)
|
||||
|
||||
Die befehle ändern sich wie folgt:
|
||||
|
||||
==> Schlüsselpaar Erzeuge
|
||||
`./opentoken --privkey <path-to-private-key> --pubkey <path-to-public-key> --genkey`
|
||||
|
||||
z.B. `./opentoken --privkey private.key --pubkey public.key --genkey`
|
||||
|
||||
==> Codes Erzeugen und versenden
|
||||
`./opentoken --config <path-to-config-key> --pubkey <path-to-public-key> --send --safe .\out\credentials.json --mails <path-to-mail-list> -html <path-to-html-template>`
|
||||
|
||||
z.B. `./opentoken --config config.json --pubkey public.key --send --safe .\out\credentials.json --mails mail.txt -html template.html`
|
||||
|
||||
==> Safe entschlüsseln
|
||||
`./opentoken --privkey <path-to-private-key> --decrypt --safe .\out\credentials.json`
|
||||
|
||||
z.B. `./opentoken --privkey private.key --decrypt --safe .\out\credentials.json`
|
||||
|
||||
## Ausführen des Quellcodes
|
||||
Der Sourcecode kann auch über ts-node ausgeführt werden.
|
||||
Dazu ist Node.js Version 12 zu verwenden
|
||||
|
||||
`nvm use 12`
|
||||
|
||||
Zum Ausführen sind folgende npm Pakete notwendig:
|
||||
- typescript
|
||||
- tslint
|
||||
- ts-node
|
||||
|
||||
Installerien sie diese mit:
|
||||
`npm install -g typescript tslint ts-node`
|
||||
|
||||
Clonen sie dieses Repository auf ihren lokalen rechner und wechseln sie anschließend in dessen verzeichniss:
|
||||
|
||||
`git clone https://gitlab.dennisgunia.de/dennisgunia/one-time-code-js.git`
|
||||
|
||||
`cd one-time-code-js`
|
||||
|
||||
Installieren sie alle lokalen npm Pakete
|
||||
|
||||
`npm install`
|
||||
|
||||
Kopieren Sie die Config-Template und passen Sie die SMTP-Zugangsdaten an:
|
||||
|
||||
`cp config.template.json config.json`
|
||||
|
||||
`vim config.json`
|
||||
|
||||
Das Skript kann nun über `npm run-script exec` oder `ts-node index.js` ausgeführt werden.
|
||||
|
||||
## Packen des Quellcodes
|
||||
Zum Packen des Quellcodes ist das npm-Paket `pkg` zu installieren:
|
||||
|
||||
`npm install -g pkg`
|
||||
|
||||
Anschließend wird der Code in JS transpiliert und durch pkg gepackt:
|
||||
|
||||
`npm run-script build`
|
||||
|
||||
Die Binaries werden in `./bin` gespeichert. Diese sind auch auf Systemen ohne node.js ausführbar.
|
||||
|
||||
## Was landet im Safe?
|
||||
Im safe landen die verschlüsselten Zuordnungen zwischen Codes und Mailadressen.
|
||||
|
||||
Zudem werden die verwendeten Codes und die bereits gesendeten Mailadressen seperat voneinander und zufällig gemischt in Klartext gespeichert.
|
||||
|
||||
Dies ermöglicht es, nachträglich benutzer hinzuzufügen, ohne allen anderen neue Mails oder gar neue Codes zukommen lassen zu müssen.
|
||||
|
||||
Es ist jedoch nocht empfohlen, nachträglich mails hinzuzufügen, da dies, abhängig von der Menge der gleichzeitig hinzugefügten Adressen eine grobe oder ggf. auch sehr genaue zuordnung zwischen Code und Mail der Nachzügler möglich ist.
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
35
dist/index.js
vendored
35
dist/index.js
vendored
@@ -22,7 +22,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var fs = __importStar(require("fs"));
|
||||
var generate_1 = require("./src/generate");
|
||||
var vault_1 = require("./src/vault");
|
||||
var configPath = "", action = -1, pubKey = "", privKey = "", safeFile = "", mails = "", html = "";
|
||||
var configPath = "", action = -1, pubKey = "", privKey = "", safeFile = "", mails = "", html = "", dryrun = false, force = false;
|
||||
for (var i = 1; i < process.argv.length; i++) {
|
||||
if (process.argv[i] === "--config") {
|
||||
if (i + 1 < process.argv.length && !process.argv[i + 1].startsWith("--")) {
|
||||
@@ -81,6 +81,12 @@ for (var i = 1; i < process.argv.length; i++) {
|
||||
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");
|
||||
@@ -107,18 +113,39 @@ if (action == 1) {
|
||||
var dataSafe_1 = new vault_1.SecureVault(pubKey, privKey);
|
||||
var confRaw = fs.readFileSync(configPath, 'utf8');
|
||||
var config = {};
|
||||
var addition_1 = false;
|
||||
config = JSON.parse(confRaw);
|
||||
if (fs.existsSync(safeFile)) {
|
||||
dataSafe_1.loadData(safeFile);
|
||||
config.usedTokens = dataSafe_1.getStorage(dataSafe_1.findStorage("usedTokens")[0].u);
|
||||
config.usedMails = dataSafe_1.getStorage(dataSafe_1.findStorage("usedMails")[0].u);
|
||||
addition_1 = 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);
|
||||
}
|
||||
generate_1.generateToken(config, dataSafe_1).then(function (el) {
|
||||
console.log(el);
|
||||
dataSafe_1.saveData(safeFile);
|
||||
if (addition_1) {
|
||||
dataSafe_1.setStorage(dataSafe_1.findStorage("usedTokens")[0].u, el.codes);
|
||||
dataSafe_1.setStorage(dataSafe_1.findStorage("usedMails")[0].u, el.mails);
|
||||
dataSafe_1.saveData(safeFile);
|
||||
}
|
||||
else {
|
||||
dataSafe_1.pushStorage('usedTokens', el.codes);
|
||||
dataSafe_1.pushStorage('usedMails', el.mails);
|
||||
dataSafe_1.saveData(safeFile);
|
||||
}
|
||||
}).catch(function (err) { return console.error("error", err); });
|
||||
}
|
||||
else if (action == 2) {
|
||||
|
||||
118
dist/src/generate.js
vendored
118
dist/src/generate.js
vendored
@@ -54,55 +54,66 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
||||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
||||
}
|
||||
};
|
||||
var __spreadArrays = (this && this.__spreadArrays) || function () {
|
||||
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
|
||||
for (var r = Array(s), k = 0, i = 0; i < il; i++)
|
||||
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
|
||||
r[k] = a[j];
|
||||
return r;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.generateToken = void 0;
|
||||
var fs = __importStar(require("fs"));
|
||||
var path = __importStar(require("path"));
|
||||
var nodemailer = __importStar(require("nodemailer"));
|
||||
var cliProgress = __importStar(require("cli-progress"));
|
||||
var shuffle_1 = require("./util/shuffle");
|
||||
var token_1 = require("./util/token");
|
||||
var Handlebars = __importStar(require("handlebars"));
|
||||
var mailParser_1 = require("./mailParser");
|
||||
function generateToken(config, dataSafe) {
|
||||
var pr = new Promise(function (resolve, error) {
|
||||
var mailArray = [];
|
||||
var readline = require('readline'), instream = fs.createReadStream(config.inFileMail), outstream = new (require('stream'))(), rl = readline.createInterface(instream, outstream);
|
||||
rl.on('line', function (line) {
|
||||
console.log(line);
|
||||
mailArray.push({
|
||||
mail: line.substr(0, line.indexOf(";")),
|
||||
name: line.substr(line.indexOf(";") + 1)
|
||||
});
|
||||
});
|
||||
rl.on('close', function (line) {
|
||||
generateCodes(resolve, error, mailArray, config, dataSafe);
|
||||
return new Promise(function (resolve, error) {
|
||||
mailParser_1.parseMails(config).then(function (res) {
|
||||
generateCodes(resolve, error, res, config, dataSafe);
|
||||
});
|
||||
});
|
||||
return pr;
|
||||
}
|
||||
exports.generateToken = generateToken;
|
||||
function generateCodes(resolve, error, mailArray, config, dataSafe) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
var codeArray, checkString, listString, i, code;
|
||||
var pbar, position, codeArray, checkString, listString, i, code;
|
||||
return __generator(this, function (_a) {
|
||||
console.log("\nGenerating codes");
|
||||
pbar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
|
||||
pbar.start(mailArray.length, 0, {
|
||||
speed: "N/A"
|
||||
});
|
||||
position = 0;
|
||||
codeArray = [];
|
||||
checkString = '';
|
||||
listString = '';
|
||||
for (i = 0; i < mailArray.length; i++) {
|
||||
code = token_1.mkstring(4);
|
||||
while (codeArray.includes(code)) {
|
||||
code = '';
|
||||
do {
|
||||
code = token_1.mkstring(4);
|
||||
}
|
||||
} while ((config.force ? codeArray : __spreadArrays(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();
|
||||
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);
|
||||
return [2];
|
||||
@@ -111,7 +122,7 @@ function generateCodes(resolve, error, mailArray, config, dataSafe) {
|
||||
}
|
||||
function sendMails(resolve, error, mailArray, codeArray, config, dataSafe) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
var mailserver, template, htmlSrc, i;
|
||||
var mailserver, template, htmlSrc, pbar, position, i;
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
@@ -124,26 +135,47 @@ function sendMails(resolve, error, mailArray, codeArray, config, dataSafe) {
|
||||
console.error("Cannote read template file!");
|
||||
error(error);
|
||||
}
|
||||
console.log("\nSending mails");
|
||||
pbar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
|
||||
pbar.start(mailArray.length, 0, {
|
||||
speed: "N/A"
|
||||
});
|
||||
position = 0;
|
||||
shuffle_1.shuffleArray(mailArray);
|
||||
shuffle_1.shuffleArray(codeArray);
|
||||
if (config.force) {
|
||||
dataSafe.clearVault();
|
||||
}
|
||||
i = 0;
|
||||
_a.label = 1;
|
||||
case 1:
|
||||
if (!(i < mailArray.length)) return [3, 4];
|
||||
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]
|
||||
});
|
||||
}
|
||||
return [4, send(mailArray[i].name, mailArray[i].mail, codeArray[i], template, mailserver, config)];
|
||||
case 2:
|
||||
_a.sent();
|
||||
position++;
|
||||
pbar.update(position);
|
||||
_a.label = 3;
|
||||
case 3:
|
||||
i++;
|
||||
return [3, 1];
|
||||
case 4:
|
||||
resolve(codeArray);
|
||||
pbar.stop();
|
||||
shuffle_1.shuffleArray(mailArray);
|
||||
shuffle_1.shuffleArray(codeArray);
|
||||
shuffle_1.shuffleArray(mailArray);
|
||||
shuffle_1.shuffleArray(codeArray);
|
||||
resolve({
|
||||
codes: config.force ? codeArray : (config.dryrun ? config.usedTokens : __spreadArrays(codeArray, config.usedTokens)),
|
||||
mails: config.force ? mailArray : (config.dryrun ? config.usedMails : __spreadArrays(mailArray, config.usedMails))
|
||||
});
|
||||
return [2];
|
||||
}
|
||||
});
|
||||
@@ -155,6 +187,13 @@ function send(name, mail, code, template, mailserver, config) {
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
if (!config.dryrun) return [3, 2];
|
||||
return [4, delay(100)];
|
||||
case 1:
|
||||
_a.sent();
|
||||
console.log("\n\u001B[36m -> dryrun: would send to " + mail + "\u001B[0m");
|
||||
return [3, 6];
|
||||
case 2:
|
||||
html = template({
|
||||
"name": name,
|
||||
"mail": mail,
|
||||
@@ -166,19 +205,26 @@ function send(name, mail, code, template, mailserver, config) {
|
||||
subject: "Dein Zugangscode zur BJR Wahl",
|
||||
html: html
|
||||
};
|
||||
_a.label = 1;
|
||||
case 1:
|
||||
_a.trys.push([1, 3, , 4]);
|
||||
return [4, mailserver.sendMail(mailOptions)];
|
||||
case 2:
|
||||
_a.sent();
|
||||
return [3, 4];
|
||||
_a.label = 3;
|
||||
case 3:
|
||||
_a.trys.push([3, 5, , 6]);
|
||||
return [4, mailserver.sendMail(mailOptions)];
|
||||
case 4:
|
||||
_a.sent();
|
||||
return [3, 6];
|
||||
case 5:
|
||||
error_1 = _a.sent();
|
||||
console.log("Error sendign mail to " + mail + " : " + error_1);
|
||||
return [3, 4];
|
||||
case 4: return [2];
|
||||
return [3, 6];
|
||||
case 6: return [2];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
function delay(t, val) {
|
||||
return new Promise(function (resolve) {
|
||||
setTimeout(function () {
|
||||
resolve(val);
|
||||
}, t);
|
||||
});
|
||||
}
|
||||
|
||||
70
dist/src/mailParser.js
vendored
Normal file
70
dist/src/mailParser.js
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.parseMails = void 0;
|
||||
var fs = __importStar(require("fs"));
|
||||
function parseMails(config) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var mailArray = [];
|
||||
var currSection = "global";
|
||||
var lineCounter = 0;
|
||||
var curCounter = 0;
|
||||
console.log("Reading mails for section " + currSection);
|
||||
var readline = require('readline'), instream = fs.createReadStream(config.inFileMail), outstream = new (require('stream'))(), rl = readline.createInterface(instream, outstream);
|
||||
rl.on('line', function (line) {
|
||||
lineCounter++;
|
||||
if (line.startsWith('[')) {
|
||||
if (line.endsWith(']')) {
|
||||
console.log("Read " + curCounter + " adresses for section " + currSection);
|
||||
curCounter = 0;
|
||||
currSection = line.substring(1, line.length - 1);
|
||||
console.log("Reading mails for section " + currSection);
|
||||
}
|
||||
else {
|
||||
console.error("Error parsing section on line " + lineCounter + ": Syntax Error. Missing closing bracket ]");
|
||||
}
|
||||
}
|
||||
else if (!line.startsWith('#')) {
|
||||
var ix_1 = line.indexOf(";");
|
||||
if (ix_1 !== -1) {
|
||||
if (config.force || config.usedMails.filter(function (el) { return el.mail == line.substr(0, ix_1); }).length == 0) {
|
||||
mailArray.push({
|
||||
mail: line.substr(0, ix_1),
|
||||
name: line.substr(ix_1 + 1)
|
||||
});
|
||||
curCounter++;
|
||||
}
|
||||
else {
|
||||
console.error("Skipping " + line.substr(0, ix_1) + ": Already sent");
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.error("Error parsing mail on line " + lineCounter + ": Syntax Error. Missing ;");
|
||||
}
|
||||
}
|
||||
});
|
||||
rl.on('close', function (line) {
|
||||
console.log("Read " + curCounter + " adresses for section " + currSection + "\n" + mailArray.length + " mails read!");
|
||||
resolve(mailArray);
|
||||
});
|
||||
});
|
||||
}
|
||||
exports.parseMails = parseMails;
|
||||
74
dist/src/vault.js
vendored
74
dist/src/vault.js
vendored
@@ -60,11 +60,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.SecureVault = void 0;
|
||||
var crypto = __importStar(require("crypto"));
|
||||
var uuid = __importStar(require("uuid"));
|
||||
var path_1 = __importDefault(require("path"));
|
||||
var fs = __importStar(require("fs"));
|
||||
var crypto_1 = require("crypto");
|
||||
var vaultVersion = 'v1.2';
|
||||
var SecureVault = (function () {
|
||||
function SecureVault(publicKey, privateKey) {
|
||||
this.storage = [];
|
||||
this.safe = {
|
||||
items: [],
|
||||
publicKey: publicKey ? fs.readFileSync(path_1.default.resolve(publicKey)) : undefined,
|
||||
@@ -75,7 +78,7 @@ var SecureVault = (function () {
|
||||
}
|
||||
SecureVault.prototype.pushData = function (data) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
var txtData, key, iv, cipher, encrypted, buffer, asym_encrypted;
|
||||
var txtData, key, iv, cipher, encrypted, buffer, asym_encrypted, u;
|
||||
return __generator(this, function (_a) {
|
||||
txtData = JSON.stringify(data);
|
||||
key = crypto.randomBytes(32);
|
||||
@@ -88,27 +91,45 @@ var SecureVault = (function () {
|
||||
throw new Error("Public Key not found");
|
||||
}
|
||||
asym_encrypted = crypto.publicEncrypt(this.safe.publicKey, buffer);
|
||||
u = uuid.v4();
|
||||
this.safe.items.push({
|
||||
u: u,
|
||||
d: encrypted.toString('hex'),
|
||||
k: asym_encrypted.toString("base64"),
|
||||
iv: iv.toString('hex')
|
||||
});
|
||||
return [2];
|
||||
return [2, u];
|
||||
});
|
||||
});
|
||||
};
|
||||
SecureVault.prototype.saveData = function (path) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
return __generator(this, function (_a) {
|
||||
fs.writeFileSync(path, JSON.stringify(this.safe.items));
|
||||
fs.writeFileSync(path, JSON.stringify({
|
||||
version: vaultVersion,
|
||||
vault: this.safe.items,
|
||||
storage: this.storage
|
||||
}));
|
||||
return [2];
|
||||
});
|
||||
});
|
||||
};
|
||||
SecureVault.prototype.loadData = function (path) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
var loaded;
|
||||
return __generator(this, function (_a) {
|
||||
this.safe.items = JSON.parse(fs.readFileSync(path, 'utf8'));
|
||||
loaded = JSON.parse(fs.readFileSync(path, 'utf8'));
|
||||
switch (loaded.version) {
|
||||
case 'v1.1':
|
||||
this.safe.items = loaded.vault;
|
||||
break;
|
||||
case 'v1.2':
|
||||
this.safe.items = loaded.vault;
|
||||
this.storage = loaded.storage;
|
||||
break;
|
||||
default:
|
||||
console.error("Unknown or unsupported vault file version: " + loaded.version);
|
||||
}
|
||||
return [2];
|
||||
});
|
||||
});
|
||||
@@ -151,6 +172,51 @@ var SecureVault = (function () {
|
||||
fs.writeFileSync(publicKeyDir, publicKey);
|
||||
});
|
||||
};
|
||||
SecureVault.prototype.pushStorage = function (tag, data) {
|
||||
if (vaultVersion !== 'v1.2') {
|
||||
throw new Error("Storage not supported in " + vaultVersion);
|
||||
}
|
||||
else {
|
||||
var objJsonStr = JSON.stringify(data);
|
||||
var objJsonB64 = Buffer.from(objJsonStr).toString("base64");
|
||||
this.storage.push({
|
||||
u: uuid.v4(),
|
||||
d: objJsonB64,
|
||||
t: tag
|
||||
});
|
||||
}
|
||||
};
|
||||
SecureVault.prototype.setStorage = function (suuid, data) {
|
||||
if (vaultVersion !== 'v1.2') {
|
||||
throw new Error("Storage not supported in " + vaultVersion);
|
||||
}
|
||||
else {
|
||||
var objJsonStr = JSON.stringify(data);
|
||||
var objJsonB64 = Buffer.from(objJsonStr, "utf8").toString("base64");
|
||||
this.storage.filter(function (el) { return el.u == suuid; })[0].d = objJsonB64;
|
||||
}
|
||||
};
|
||||
SecureVault.prototype.getStorage = function (suuid) {
|
||||
if (vaultVersion !== 'v1.2') {
|
||||
throw new Error("Storage not supported in " + vaultVersion);
|
||||
}
|
||||
else {
|
||||
var data = this.storage.filter(function (el) { return el.u == suuid; })[0];
|
||||
var objJsonB64 = new Buffer(data.d, 'base64');
|
||||
return JSON.parse(objJsonB64.toString('utf8'));
|
||||
}
|
||||
};
|
||||
SecureVault.prototype.findStorage = function (tag) {
|
||||
if (vaultVersion !== 'v1.2') {
|
||||
throw new Error("Storage not supported in " + vaultVersion);
|
||||
}
|
||||
else {
|
||||
return this.storage.filter(function (el) { return el.t == tag; });
|
||||
}
|
||||
};
|
||||
SecureVault.prototype.clearVault = function () {
|
||||
this.safe.items = [];
|
||||
};
|
||||
return SecureVault;
|
||||
}());
|
||||
exports.SecureVault = SecureVault;
|
||||
|
||||
33
index.ts
33
index.ts
@@ -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
67
package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -5,24 +5,29 @@
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"exec": "ts-node index.ts",
|
||||
"build": "rm bin/* -f && rm dist/* -Rf && tsc && pkg . --out-path bin --targets linux,macos,win"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
|
||||
190
src/generate.js
190
src/generate.js
@@ -1,190 +0,0 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __generator = (this && this.__generator) || function (thisArg, body) {
|
||||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
||||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
||||
function verb(n) { return function (v) { return step([n, v]); }; }
|
||||
function step(op) {
|
||||
if (f) throw new TypeError("Generator is already executing.");
|
||||
while (_) try {
|
||||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
||||
if (y = 0, t) op = [op[0] & 2, t.value];
|
||||
switch (op[0]) {
|
||||
case 0: case 1: t = op; break;
|
||||
case 4: _.label++; return { value: op[1], done: false };
|
||||
case 5: _.label++; y = op[1]; op = [0]; continue;
|
||||
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
||||
default:
|
||||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
||||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
||||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
||||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
||||
if (t[2]) _.ops.pop();
|
||||
_.trys.pop(); continue;
|
||||
}
|
||||
op = body.call(thisArg, _);
|
||||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
||||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
||||
}
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.generateToken = void 0;
|
||||
var fs = __importStar(require("fs"));
|
||||
var nodemailer = __importStar(require("nodemailer"));
|
||||
var shuffle_1 = require("./util/shuffle");
|
||||
var token_1 = require("./util/token");
|
||||
var Handlebars = __importStar(require("handlebars"));
|
||||
function generateToken(config, dataSafe) {
|
||||
var pr = new Promise(function (resolve, error) {
|
||||
var mailArray = [];
|
||||
// read and process mail list
|
||||
var readline = require('readline'), instream = fs.createReadStream(config.inFileMail), outstream = new (require('stream'))(), rl = readline.createInterface(instream, outstream);
|
||||
rl.on('line', function (line) {
|
||||
console.log(line);
|
||||
mailArray.push({
|
||||
mail: line.substr(0, line.indexOf(";")),
|
||||
name: line.substr(line.indexOf(";") + 1)
|
||||
});
|
||||
});
|
||||
rl.on('close', function (line) {
|
||||
// next step
|
||||
generateCodes(resolve, error, mailArray, config, dataSafe);
|
||||
});
|
||||
});
|
||||
return pr;
|
||||
}
|
||||
exports.generateToken = generateToken;
|
||||
// generate codes
|
||||
function generateCodes(resolve, error, mailArray, config, dataSafe) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
var codeArray, checkString, listString, i, code;
|
||||
return __generator(this, function (_a) {
|
||||
codeArray = [];
|
||||
checkString = '';
|
||||
listString = '';
|
||||
for (i = 0; i < mailArray.length; i++) { // as many codes as adresses
|
||||
code = token_1.mkstring(4);
|
||||
while (codeArray.includes(code)) {
|
||||
code = token_1.mkstring(4);
|
||||
}
|
||||
codeArray.push(code);
|
||||
checkString = checkString + "|" + code;
|
||||
listString = listString + "\n" + code;
|
||||
}
|
||||
checkString = checkString.substr(1);
|
||||
listString = listString.substr(1);
|
||||
//write code lists
|
||||
try {
|
||||
fs.writeFileSync(config.outFileMatch, checkString);
|
||||
fs.writeFileSync(config.outFileCodes, listString);
|
||||
}
|
||||
catch (error) {
|
||||
error(error);
|
||||
}
|
||||
sendMails(resolve, error, mailArray, codeArray, config, dataSafe);
|
||||
return [2 /*return*/];
|
||||
});
|
||||
});
|
||||
}
|
||||
// randomize mails and tokens
|
||||
function sendMails(resolve, error, mailArray, codeArray, config, dataSafe) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
var mailserver, template, htmlSrc, i;
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
mailserver = nodemailer.createTransport(config.mail);
|
||||
try {
|
||||
htmlSrc = fs.readFileSync(config.htmlPath, "utf8");
|
||||
template = Handlebars.compile(htmlSrc);
|
||||
}
|
||||
catch (error) {
|
||||
console.error("Cannote read template file!");
|
||||
error(error);
|
||||
}
|
||||
shuffle_1.shuffleArray(mailArray);
|
||||
shuffle_1.shuffleArray(codeArray);
|
||||
i = 0;
|
||||
_a.label = 1;
|
||||
case 1:
|
||||
if (!(i < mailArray.length)) return [3 /*break*/, 4];
|
||||
// send mail
|
||||
dataSafe.pushData({
|
||||
name: mailArray[i].name,
|
||||
mail: mailArray[i].mail,
|
||||
code: codeArray[i]
|
||||
});
|
||||
return [4 /*yield*/, send(mailArray[i].name, mailArray[i].mail, codeArray[i], template, mailserver, config)];
|
||||
case 2:
|
||||
_a.sent();
|
||||
_a.label = 3;
|
||||
case 3:
|
||||
i++;
|
||||
return [3 /*break*/, 1];
|
||||
case 4:
|
||||
resolve(codeArray);
|
||||
return [2 /*return*/];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
function send(name, mail, code, template, mailserver, config) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
var html, mailOptions, error_1;
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
html = template({
|
||||
"name": name,
|
||||
"mail": mail,
|
||||
"code": code
|
||||
});
|
||||
mailOptions = {
|
||||
from: config.mailFrom + " <" + config.mail.auth.user + ">",
|
||||
to: mail,
|
||||
subject: "Dein Zugangscode zur BJR Wahl",
|
||||
html: html
|
||||
};
|
||||
_a.label = 1;
|
||||
case 1:
|
||||
_a.trys.push([1, 3, , 4]);
|
||||
return [4 /*yield*/, mailserver.sendMail(mailOptions)];
|
||||
case 2:
|
||||
_a.sent();
|
||||
return [3 /*break*/, 4];
|
||||
case 3:
|
||||
error_1 = _a.sent();
|
||||
console.log("Error sendign mail to " + mail + " : " + error_1);
|
||||
return [3 /*break*/, 4];
|
||||
case 4: return [2 /*return*/];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
143
src/generate.ts
143
src/generate.ts
@@ -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);
|
||||
});
|
||||
}
|
||||
63
src/mailParser.ts
Normal file
63
src/mailParser.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { rejects } from "assert";
|
||||
import * as fs from 'fs'
|
||||
import { Console } from "console";
|
||||
|
||||
export interface MLItem{
|
||||
mail: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export function parseMails(config: any) {
|
||||
return new Promise<MLItem[]>((resolve,reject) => {
|
||||
let mailArray: MLItem[] = [];
|
||||
let currSection: string = "global";
|
||||
let lineCounter: number = 0;
|
||||
let curCounter: number = 0;
|
||||
|
||||
|
||||
console.log(`Reading mails for section ${currSection}`)
|
||||
// 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) {
|
||||
lineCounter ++;
|
||||
if(line.startsWith('[')){
|
||||
if(line.endsWith(']')){
|
||||
console.log(`Read ${curCounter} adresses for section ${currSection}`)
|
||||
curCounter = 0;
|
||||
currSection=line.substring(1,line.length -1);
|
||||
console.log(`Reading mails for section ${currSection}`)
|
||||
}else{
|
||||
console.error(`Error parsing section on line ${lineCounter}: Syntax Error. Missing closing bracket ]`)
|
||||
}
|
||||
}else if (!line.startsWith('#')){
|
||||
const ix = line.indexOf(";")
|
||||
if (ix !== -1){
|
||||
// check if already exist
|
||||
if (config.force || config.usedMails.filter((el: MLItem) => el.mail == line.substr(0,ix)).length == 0){
|
||||
mailArray.push({
|
||||
mail: line.substr(0,ix),
|
||||
name: line.substr(ix + 1)
|
||||
})
|
||||
curCounter ++;
|
||||
}else{
|
||||
console.error(`Skipping ${line.substr(0,ix)}: Already sent`)
|
||||
}
|
||||
}else{
|
||||
console.error(`Error parsing mail on line ${lineCounter}: Syntax Error. Missing ;`)
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
rl.on('close', function (line:string) {
|
||||
// next step
|
||||
console.log(`Read ${curCounter} adresses for section ${currSection}\n${mailArray.length} mails read!`)
|
||||
resolve(mailArray);
|
||||
});
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.shuffleArray = void 0;
|
||||
function shuffleArray(array) {
|
||||
for (var i = array.length - 1; i > 0; i--) {
|
||||
var j = Math.floor(Math.random() * (i + 1));
|
||||
var temp = array[i];
|
||||
array[i] = array[j];
|
||||
array[j] = temp;
|
||||
}
|
||||
}
|
||||
exports.shuffleArray = shuffleArray;
|
||||
@@ -1,13 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.mkstring = void 0;
|
||||
function mkstring(length) {
|
||||
var result = '';
|
||||
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
var charactersLength = characters.length;
|
||||
for (var i = 0; i < length; i++) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
exports.mkstring = mkstring;
|
||||
158
src/vault.js
158
src/vault.js
@@ -1,158 +0,0 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __generator = (this && this.__generator) || function (thisArg, body) {
|
||||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
||||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
||||
function verb(n) { return function (v) { return step([n, v]); }; }
|
||||
function step(op) {
|
||||
if (f) throw new TypeError("Generator is already executing.");
|
||||
while (_) try {
|
||||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
||||
if (y = 0, t) op = [op[0] & 2, t.value];
|
||||
switch (op[0]) {
|
||||
case 0: case 1: t = op; break;
|
||||
case 4: _.label++; return { value: op[1], done: false };
|
||||
case 5: _.label++; y = op[1]; op = [0]; continue;
|
||||
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
||||
default:
|
||||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
||||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
||||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
||||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
||||
if (t[2]) _.ops.pop();
|
||||
_.trys.pop(); continue;
|
||||
}
|
||||
op = body.call(thisArg, _);
|
||||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
||||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
||||
}
|
||||
};
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.SecureVault = void 0;
|
||||
var crypto = __importStar(require("crypto"));
|
||||
var path_1 = __importDefault(require("path"));
|
||||
var fs = __importStar(require("fs"));
|
||||
var crypto_1 = require("crypto");
|
||||
var SecureVault = /** @class */ (function () {
|
||||
function SecureVault(publicKey, privateKey) {
|
||||
this.safe = {
|
||||
items: [],
|
||||
publicKey: publicKey ? fs.readFileSync(path_1.default.resolve(publicKey)) : undefined,
|
||||
privateKey: privateKey ? fs.readFileSync(path_1.default.resolve(privateKey)) : undefined
|
||||
};
|
||||
this.privPath = publicKey ? path_1.default.resolve(publicKey) : undefined,
|
||||
this.pubPath = privateKey ? path_1.default.resolve(privateKey) : undefined;
|
||||
}
|
||||
SecureVault.prototype.pushData = function (data) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
var txtData, key, iv, cipher, encrypted, buffer, asym_encrypted;
|
||||
return __generator(this, function (_a) {
|
||||
txtData = JSON.stringify(data);
|
||||
key = crypto.randomBytes(32);
|
||||
iv = crypto.randomBytes(16);
|
||||
cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key), iv);
|
||||
encrypted = cipher.update(txtData);
|
||||
encrypted = Buffer.concat([encrypted, cipher.final()]);
|
||||
buffer = new Buffer(key);
|
||||
if (!this.safe.publicKey) {
|
||||
throw new Error("Public Key not found");
|
||||
}
|
||||
asym_encrypted = crypto.publicEncrypt(this.safe.publicKey, buffer);
|
||||
this.safe.items.push({
|
||||
d: encrypted.toString('hex'),
|
||||
k: asym_encrypted.toString("base64"),
|
||||
iv: iv.toString('hex')
|
||||
});
|
||||
return [2 /*return*/];
|
||||
});
|
||||
});
|
||||
};
|
||||
SecureVault.prototype.saveData = function (path) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
return __generator(this, function (_a) {
|
||||
fs.writeFileSync(path, JSON.stringify(this.safe.items));
|
||||
return [2 /*return*/];
|
||||
});
|
||||
});
|
||||
};
|
||||
SecureVault.prototype.loadData = function (path) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
return __generator(this, function (_a) {
|
||||
this.safe.items = JSON.parse(fs.readFileSync(path, 'utf8'));
|
||||
return [2 /*return*/];
|
||||
});
|
||||
});
|
||||
};
|
||||
SecureVault.prototype.decryptData = function () {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
var _this = this;
|
||||
return __generator(this, function (_a) {
|
||||
this.safe.items.forEach(function (el) {
|
||||
// decrpyt key
|
||||
var buffer = new Buffer(el.k, "base64");
|
||||
if (!_this.safe.privateKey) {
|
||||
throw new Error("Private Key not found");
|
||||
}
|
||||
var key = crypto.privateDecrypt(_this.safe.privateKey, buffer);
|
||||
// decrpyt payload
|
||||
var iv = Buffer.from(el.iv, 'hex');
|
||||
var encryptedText = Buffer.from(el.d, 'hex');
|
||||
var decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
|
||||
var decrypted = decipher.update(encryptedText);
|
||||
decrypted = Buffer.concat([decrypted, decipher.final()]);
|
||||
var obj = JSON.parse(decrypted.toString());
|
||||
console.log(obj);
|
||||
});
|
||||
return [2 /*return*/];
|
||||
});
|
||||
});
|
||||
};
|
||||
SecureVault.genKey = function (publicKeyDir, privateKeyDir) {
|
||||
crypto_1.generateKeyPair('rsa', {
|
||||
modulusLength: 4096,
|
||||
publicKeyEncoding: {
|
||||
type: 'pkcs1',
|
||||
format: 'pem'
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
type: 'pkcs1',
|
||||
format: 'pem',
|
||||
}
|
||||
}, function (err, publicKey, privateKey) {
|
||||
fs.writeFileSync(privateKeyDir, privateKey);
|
||||
fs.writeFileSync(publicKeyDir, publicKey);
|
||||
});
|
||||
};
|
||||
return SecureVault;
|
||||
}());
|
||||
exports.SecureVault = SecureVault;
|
||||
84
src/vault.ts
84
src/vault.ts
@@ -1,14 +1,25 @@
|
||||
import * as crypto from 'crypto'
|
||||
import * as uuid from 'uuid'
|
||||
import path from 'path';
|
||||
import * as fs from 'fs'
|
||||
import { generateKeyPair } from 'crypto';
|
||||
import { Console } from 'console';
|
||||
|
||||
const vaultVersion = 'v1.2'
|
||||
|
||||
export interface SecureVaultItem {
|
||||
u: string; // uuid
|
||||
d: string; // data
|
||||
k: string; // key
|
||||
iv: string; // init vector
|
||||
}
|
||||
|
||||
export interface StorageItem {
|
||||
u: string; // uuid
|
||||
d: string; // data
|
||||
t: string; // tag
|
||||
}
|
||||
|
||||
export interface secureVaultList {
|
||||
items: SecureVaultItem[];
|
||||
publicKey?: Buffer;
|
||||
@@ -20,8 +31,10 @@ export class SecureVault {
|
||||
safe: secureVaultList;
|
||||
privPath?: string;
|
||||
pubPath?: string;
|
||||
storage: StorageItem[];
|
||||
|
||||
constructor (publicKey: string, privateKey?: string) {
|
||||
this.storage = [];
|
||||
this.safe = {
|
||||
items: [],
|
||||
publicKey: publicKey ?fs.readFileSync(path.resolve(publicKey)): undefined,
|
||||
@@ -31,7 +44,7 @@ export class SecureVault {
|
||||
this.pubPath = privateKey ? path.resolve(privateKey): undefined
|
||||
}
|
||||
|
||||
async pushData(data: any): Promise<void>{
|
||||
async pushData(data: any): Promise<string>{
|
||||
// encrypt payload
|
||||
const txtData = JSON.stringify(data);
|
||||
const key = crypto.randomBytes(32);
|
||||
@@ -45,20 +58,38 @@ export class SecureVault {
|
||||
throw new Error("Public Key not found");
|
||||
}
|
||||
var asym_encrypted = crypto.publicEncrypt(this.safe.publicKey, buffer);
|
||||
|
||||
const u = uuid.v4()
|
||||
this.safe.items.push({
|
||||
u,
|
||||
d: encrypted.toString('hex'),
|
||||
k: asym_encrypted.toString("base64"),
|
||||
iv: iv.toString('hex')
|
||||
})
|
||||
return u;
|
||||
}
|
||||
|
||||
async saveData(path: string): Promise<void>{
|
||||
fs.writeFileSync(path, JSON.stringify(this.safe.items));
|
||||
fs.writeFileSync(path, JSON.stringify({
|
||||
version: vaultVersion,
|
||||
vault: this.safe.items,
|
||||
storage: this.storage
|
||||
}));
|
||||
}
|
||||
|
||||
async loadData(path: string): Promise<void>{
|
||||
this.safe.items = JSON.parse(fs.readFileSync(path, 'utf8'))
|
||||
const loaded = JSON.parse(fs.readFileSync(path, 'utf8'));
|
||||
switch (loaded.version){
|
||||
case 'v1.1':
|
||||
this.safe.items = loaded.vault;
|
||||
break;
|
||||
case 'v1.2':
|
||||
this.safe.items = loaded.vault;
|
||||
this.storage = loaded.storage;
|
||||
break;
|
||||
default:
|
||||
console.error(`Unknown or unsupported vault file version: ${loaded.version}`)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async decryptData(): Promise<void>{
|
||||
@@ -98,4 +129,49 @@ export class SecureVault {
|
||||
});
|
||||
}
|
||||
|
||||
pushStorage(tag:string, data: any){
|
||||
if (vaultVersion !== 'v1.2'){
|
||||
throw new Error(`Storage not supported in ${vaultVersion}`);
|
||||
}else{
|
||||
let objJsonStr = JSON.stringify(data);
|
||||
let objJsonB64 = Buffer.from(objJsonStr).toString("base64");
|
||||
this.storage.push({
|
||||
u: uuid.v4(),
|
||||
d: objJsonB64,
|
||||
t: tag
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setStorage(suuid:string, data: any){
|
||||
if (vaultVersion !== 'v1.2'){
|
||||
throw new Error(`Storage not supported in ${vaultVersion}`);
|
||||
}else{
|
||||
let objJsonStr = JSON.stringify(data);
|
||||
let objJsonB64 = Buffer.from(objJsonStr,"utf8").toString("base64");
|
||||
this.storage.filter(el => el.u == suuid)[0].d = objJsonB64;
|
||||
}
|
||||
}
|
||||
|
||||
getStorage(suuid:string){
|
||||
if (vaultVersion !== 'v1.2'){
|
||||
throw new Error(`Storage not supported in ${vaultVersion}`);
|
||||
}else{
|
||||
const data = this.storage.filter(el => el.u == suuid)[0];
|
||||
let objJsonB64 = new Buffer(data.d, 'base64');
|
||||
return JSON.parse(objJsonB64.toString('utf8'));
|
||||
}
|
||||
}
|
||||
|
||||
findStorage(tag:string){
|
||||
if (vaultVersion !== 'v1.2'){
|
||||
throw new Error(`Storage not supported in ${vaultVersion}`);
|
||||
}else{
|
||||
return this.storage.filter(el => el.t == tag);
|
||||
}
|
||||
}
|
||||
|
||||
clearVault(){
|
||||
this.safe.items = [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user