diff --git a/check-account-deletion.js b/check-account-deletion.js new file mode 100644 index 000000000..39bbf02f5 --- /dev/null +++ b/check-account-deletion.js @@ -0,0 +1,76 @@ +/* jshint esversion: 6, node: true */ +const Fs = require('fs'); +const nThen = require('nthen'); +const Pinned = require('./pinned'); +const Nacl = require('tweetnacl'); + +const hashesFromPinFile = (pinFile, fileName) => { + var pins = {}; + pinFile.split('\n').filter((x)=>(x)).map((l) => JSON.parse(l)).forEach((l) => { + switch (l[0]) { + case 'RESET': { + pins = {}; + if (l[1] && l[1].length) { l[1].forEach((x) => { pins[x] = 1; }); } + //jshint -W086 + // fallthrough + } + case 'PIN': { + l[1].forEach((x) => { pins[x] = 1; }); + break; + } + case 'UNPIN': { + l[1].forEach((x) => { delete pins[x]; }); + break; + } + default: throw new Error(JSON.stringify(l) + ' ' + fileName); + } + }); + return Object.keys(pins); +}; + +var escapeKeyCharacters = function (key) { + return key && key.replace && key.replace(/\//g, '-'); +}; + + +const dataIdx = process.argv.indexOf('--data'); +let edPublic; +if (dataIdx === -1) { + const hasEdPublic = process.argv.indexOf('--ed'); + if (hasEdPublic === -1) { return void console.error("Missing ed argument"); } + edPublic = escapeKeyCharacters(process.argv[hasEdPublic+1]); +} else { + const deleteData = JSON.parse(process.argv[dataIdx+1]); + if (!deleteData.toSign || !deleteData.proof) { return void console.error("Invalid arguments"); } + // Check sig + const ed = Nacl.util.decodeBase64(deleteData.toSign.edPublic); + const signed = Nacl.util.decodeUTF8(JSON.stringify(deleteData.toSign)); + const proof = Nacl.util.decodeBase64(deleteData.proof); + if (!Nacl.sign.detached.verify(signed, proof, ed)) { return void console.error("Invalid signature"); } + edPublic = escapeKeyCharacters(deleteData.toSign.edPublic); +} + +let data = []; +let pinned = []; + +nThen((waitFor) => { + let f = './pins/' + edPublic.slice(0, 2) + '/' + edPublic + '.ndjson'; + Fs.readFile(f, waitFor((err, content) => { + if (err) { throw err; } + pinned = hashesFromPinFile(content.toString('utf8'), f); + })); +}).nThen((waitFor) => { + Pinned.load(waitFor((d) => { + data = Object.keys(d); + }), { + exclude: [edPublic + '.ndjson'] + }); +}).nThen(() => { + console.log('Pads pinned by this user and not pinned by anybody else:'); + pinned.forEach((p) => { + if (data.indexOf(p) === -1) { + console.log(p); + } + }); +}); + diff --git a/pinned.js b/pinned.js index 41a832241..d5df9373a 100644 --- a/pinned.js +++ b/pinned.js @@ -15,6 +15,7 @@ const hashesFromPinFile = (pinFile, fileName) => { switch (l[0]) { case 'RESET': { pins = {}; + if (l[1] && l[1].length) { l[1].forEach((x) => { pins[x] = 1; }); } //jshint -W086 // fallthrough } @@ -32,7 +33,7 @@ const hashesFromPinFile = (pinFile, fileName) => { return Object.keys(pins); }; -module.exports.load = function (cb) { +module.exports.load = function (cb, config) { nThen((waitFor) => { Fs.readdir('./pins', waitFor((err, list) => { if (err) { @@ -49,7 +50,10 @@ module.exports.load = function (cb) { sema.take((returnAfter) => { Fs.readdir('./pins/' + f, waitFor(returnAfter((err, list2) => { if (err) { throw err; } - list2.forEach((ff) => { fileList.push('./pins/' + f + '/' + ff); }); + list2.forEach((ff) => { + if (config && config.exclude && config.exclude.indexOf(ff) > -1) { return; } + fileList.push('./pins/' + f + '/' + ff); + }); }))); }); }); @@ -76,4 +80,4 @@ if (!module.parent) { console.log(x + ' ' + JSON.stringify(data[x])); }); }); -} \ No newline at end of file +} diff --git a/pinneddata.js b/pinneddata.js index 378f34ad7..f9053b9b6 100644 --- a/pinneddata.js +++ b/pinneddata.js @@ -9,6 +9,7 @@ const hashesFromPinFile = (pinFile, fileName) => { switch (l[0]) { case 'RESET': { pins = {}; + if (l[1] && l[1].length) { l[1].forEach((x) => { pins[x] = 1; }); } //jshint -W086 // fallthrough }