2019-06-27 17:11:22 +08:00
|
|
|
var Meta = module.exports;
|
|
|
|
|
2019-08-21 18:24:12 +08:00
|
|
|
var deduplicate = require("./deduplicate");
|
|
|
|
|
2019-06-27 17:11:22 +08:00
|
|
|
/* Metadata fields:
|
|
|
|
|
|
|
|
* channel <STRING>
|
|
|
|
* validateKey <STRING>
|
|
|
|
* owners <ARRAY>
|
|
|
|
* ADD_OWNERS
|
|
|
|
* RM_OWNERS
|
|
|
|
* expire <NUMBER>
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
var commands = {};
|
|
|
|
|
|
|
|
// ["ADD_OWNERS", ["7eEqelGso3EBr5jHlei6av4r9w2B9XZiGGwA1EgZ-5I="], 1561623438989]
|
|
|
|
commands.ADD_OWNERS = function (meta, args) {
|
2019-06-27 18:13:29 +08:00
|
|
|
// bail out if args isn't an array
|
2019-06-27 17:11:22 +08:00
|
|
|
if (!Array.isArray(args)) {
|
|
|
|
throw new Error('METADATA_INVALID_OWNERS');
|
|
|
|
}
|
2019-06-27 18:13:29 +08:00
|
|
|
|
|
|
|
// you shouldn't be able to get here if there are no owners
|
|
|
|
// because only an owner should be able to change the owners
|
2019-06-27 17:11:22 +08:00
|
|
|
if (!Array.isArray(meta.owners)) {
|
|
|
|
throw new Error("METADATA_NONSENSE_OWNERS");
|
|
|
|
}
|
|
|
|
|
2019-09-02 23:16:14 +08:00
|
|
|
var changed = false;
|
2019-06-27 17:11:22 +08:00
|
|
|
args.forEach(function (owner) {
|
|
|
|
if (meta.owners.indexOf(owner) >= 0) { return; }
|
|
|
|
meta.owners.push(owner);
|
2019-09-02 23:16:14 +08:00
|
|
|
changed = true;
|
2019-06-27 17:11:22 +08:00
|
|
|
});
|
2019-09-02 23:16:14 +08:00
|
|
|
|
|
|
|
return changed;
|
2019-06-27 17:11:22 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// ["RM_OWNERS", ["CrufexqXcY-z+eKJlEbNELVy5Sb7E-EAAEFI8GnEtZ0="], 1561623439989]
|
|
|
|
commands.RM_OWNERS = function (meta, args) {
|
2019-06-27 18:13:29 +08:00
|
|
|
// what are you doing if you don't have owners to remove?
|
2019-06-27 17:11:22 +08:00
|
|
|
if (!Array.isArray(args)) {
|
|
|
|
throw new Error('METADATA_INVALID_OWNERS');
|
|
|
|
}
|
2019-06-27 18:13:29 +08:00
|
|
|
// if there aren't any owners to start, this is also pointless
|
2019-06-27 17:11:22 +08:00
|
|
|
if (!Array.isArray(meta.owners)) {
|
|
|
|
throw new Error("METADATA_NONSENSE_OWNERS");
|
|
|
|
}
|
|
|
|
|
2019-09-02 23:16:14 +08:00
|
|
|
var changed = false;
|
2019-06-27 18:13:29 +08:00
|
|
|
// remove owners one by one
|
|
|
|
// we assume there are no duplicates
|
2019-06-27 17:11:22 +08:00
|
|
|
args.forEach(function (owner) {
|
|
|
|
var index = meta.owners.indexOf(owner);
|
2019-06-27 18:13:29 +08:00
|
|
|
if (index < 0) { return; }
|
2019-09-03 21:11:23 +08:00
|
|
|
if (meta.mailbox) {
|
|
|
|
if (typeof(meta.mailbox) === "string") {
|
|
|
|
delete meta.mailbox;
|
|
|
|
} else {
|
|
|
|
delete meta.mailbox[owner];
|
|
|
|
}
|
|
|
|
}
|
2019-06-27 17:11:22 +08:00
|
|
|
meta.owners.splice(index, 1);
|
2019-09-02 23:16:14 +08:00
|
|
|
changed = true;
|
2019-06-27 17:11:22 +08:00
|
|
|
});
|
2019-09-02 23:16:14 +08:00
|
|
|
|
|
|
|
return changed;
|
2019-06-27 17:11:22 +08:00
|
|
|
};
|
|
|
|
|
2019-08-30 18:07:03 +08:00
|
|
|
// ["ADD_PENDING_OWNERS", ["7eEqelGso3EBr5jHlei6av4r9w2B9XZiGGwA1EgZ-5I="], 1561623438989]
|
|
|
|
commands.ADD_PENDING_OWNERS = function (meta, args) {
|
|
|
|
// bail out if args isn't an array
|
|
|
|
if (!Array.isArray(args)) {
|
|
|
|
throw new Error('METADATA_INVALID_PENDING_OWNERS');
|
|
|
|
}
|
|
|
|
|
|
|
|
// you shouldn't be able to get here if there are no owners
|
|
|
|
// because only an owner should be able to change the owners
|
|
|
|
if (meta.pending_owners && !Array.isArray(meta.pending_owners)) {
|
|
|
|
throw new Error("METADATA_NONSENSE_PENDING_OWNERS");
|
|
|
|
}
|
|
|
|
|
2019-09-02 23:16:14 +08:00
|
|
|
var changed = false;
|
2019-08-30 18:07:03 +08:00
|
|
|
// Add pending_owners array if it doesn't exist
|
|
|
|
if (!meta.pending_owners) {
|
|
|
|
meta.pending_owners = deduplicate(args);
|
2019-09-02 23:16:14 +08:00
|
|
|
return true;
|
2019-08-30 18:07:03 +08:00
|
|
|
}
|
|
|
|
// or fill it
|
|
|
|
args.forEach(function (owner) {
|
|
|
|
if (meta.pending_owners.indexOf(owner) >= 0) { return; }
|
|
|
|
meta.pending_owners.push(owner);
|
2019-09-02 23:16:14 +08:00
|
|
|
changed = true;
|
2019-08-30 18:07:03 +08:00
|
|
|
});
|
2019-09-02 23:16:14 +08:00
|
|
|
|
|
|
|
return changed;
|
2019-08-30 18:07:03 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// ["RM_PENDING_OWNERS", ["CrufexqXcY-z+eKJlEbNELVy5Sb7E-EAAEFI8GnEtZ0="], 1561623439989]
|
|
|
|
commands.RM_PENDING_OWNERS = function (meta, args) {
|
|
|
|
// what are you doing if you don't have owners to remove?
|
|
|
|
if (!Array.isArray(args)) {
|
|
|
|
throw new Error('METADATA_INVALID_PENDING_OWNERS');
|
|
|
|
}
|
|
|
|
// if there aren't any owners to start, this is also pointless
|
|
|
|
if (!Array.isArray(meta.pending_owners)) {
|
|
|
|
throw new Error("METADATA_NONSENSE_PENDING_OWNERS");
|
|
|
|
}
|
|
|
|
|
2019-09-02 23:16:14 +08:00
|
|
|
var changed = false;
|
2019-08-30 18:07:03 +08:00
|
|
|
// remove owners one by one
|
|
|
|
// we assume there are no duplicates
|
|
|
|
args.forEach(function (owner) {
|
|
|
|
var index = meta.pending_owners.indexOf(owner);
|
|
|
|
if (index < 0) { return; }
|
|
|
|
meta.pending_owners.splice(index, 1);
|
2019-09-02 23:16:14 +08:00
|
|
|
changed = true;
|
2019-08-30 18:07:03 +08:00
|
|
|
});
|
2019-09-02 23:16:14 +08:00
|
|
|
|
|
|
|
return changed;
|
2019-08-30 18:07:03 +08:00
|
|
|
};
|
|
|
|
|
2019-06-27 18:13:29 +08:00
|
|
|
// ["RESET_OWNERS", ["7eEqelGso3EBr5jHlei6av4r9w2B9XZiGGwA1EgZ-5I="], 1561623439989]
|
|
|
|
commands.RESET_OWNERS = function (meta, args) {
|
|
|
|
// expect a new array, even if it's empty
|
|
|
|
if (!Array.isArray(args)) {
|
|
|
|
throw new Error('METADATA_INVALID_OWNERS');
|
|
|
|
}
|
|
|
|
// assume there are owners to start
|
|
|
|
if (!Array.isArray(meta.owners)) {
|
|
|
|
throw new Error("METADATA_NONSENSE_OWNERS");
|
|
|
|
}
|
|
|
|
|
|
|
|
// overwrite the existing owners with the new one
|
2019-08-21 18:24:12 +08:00
|
|
|
meta.owners = deduplicate(args);
|
2019-09-02 23:16:14 +08:00
|
|
|
return true;
|
2019-06-27 18:13:29 +08:00
|
|
|
};
|
|
|
|
|
2019-09-03 21:11:23 +08:00
|
|
|
// ["ADD_MAILBOX", {"7eEqelGso3EBr5jHlei6av4r9w2B9XZiGGwA1EgZ-5I=": mailbox, ...}, 1561623439989]
|
|
|
|
commands.ADD_MAILBOX = function (meta, args) {
|
|
|
|
// expect a new array, even if it's empty
|
|
|
|
if (!args || typeof(args) !== "object") {
|
|
|
|
throw new Error('METADATA_INVALID_MAILBOX');
|
|
|
|
}
|
|
|
|
// assume there are owners to start
|
|
|
|
if (!Array.isArray(meta.owners)) {
|
|
|
|
throw new Error("METADATA_NONSENSE_OWNERS");
|
|
|
|
}
|
|
|
|
|
|
|
|
var changed = false;
|
|
|
|
|
|
|
|
// For each mailbox we try to add, check if the associated edPublic is an owner
|
|
|
|
// If they are, add or replace the mailbox
|
|
|
|
Object.keys(args).forEach(function (edPublic) {
|
|
|
|
if (meta.owners.indexOf(edPublic) === -1) { return; }
|
|
|
|
|
|
|
|
if (typeof(meta.mailbox) === "string") {
|
|
|
|
var str = meta.mailbox;
|
|
|
|
meta.mailbox = {};
|
|
|
|
meta.mailbox[meta.owners[0]] = str;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure mailbox is defined
|
|
|
|
if (!meta.mailbox) { meta.mailbox = {}; }
|
|
|
|
|
|
|
|
meta.mailbox[edPublic] = args[edPublic];
|
|
|
|
changed = true;
|
|
|
|
});
|
|
|
|
|
|
|
|
return changed;
|
|
|
|
};
|
|
|
|
|
2019-06-27 17:11:22 +08:00
|
|
|
commands.UPDATE_EXPIRATION = function () {
|
2019-08-21 18:28:19 +08:00
|
|
|
throw new Error("E_NOT_IMPLEMENTED");
|
2019-06-27 17:11:22 +08:00
|
|
|
};
|
|
|
|
|
2019-08-30 17:49:15 +08:00
|
|
|
var handleCommand = Meta.handleCommand = function (meta, line) {
|
2019-06-27 17:11:22 +08:00
|
|
|
var command = line[0];
|
|
|
|
var args = line[1];
|
|
|
|
//var time = line[2];
|
|
|
|
|
|
|
|
if (typeof(commands[command]) !== 'function') {
|
|
|
|
throw new Error("METADATA_UNSUPPORTED_COMMAND");
|
|
|
|
}
|
|
|
|
|
2019-09-03 19:29:57 +08:00
|
|
|
return commands[command](meta, args);
|
2019-06-27 17:11:22 +08:00
|
|
|
};
|
2019-08-30 17:49:15 +08:00
|
|
|
Meta.commands = Object.keys(commands);
|
2019-06-27 17:11:22 +08:00
|
|
|
|
|
|
|
Meta.createLineHandler = function (ref, errorHandler) {
|
|
|
|
ref.meta = {};
|
2019-08-12 21:26:23 +08:00
|
|
|
ref.index = 0;
|
2019-06-27 17:11:22 +08:00
|
|
|
|
2019-06-28 00:21:12 +08:00
|
|
|
return function (err, line) {
|
2019-06-27 17:11:22 +08:00
|
|
|
if (err) {
|
2019-09-06 19:36:06 +08:00
|
|
|
// it's not abnormal that metadata exists without a corresponding log
|
|
|
|
// so ENOENT is fine
|
|
|
|
if (ref.index === 0 && err.code === 'ENOENT') { return; }
|
|
|
|
// any other errors are abnormal
|
2019-06-27 17:11:22 +08:00
|
|
|
return void errorHandler('METADATA_HANDLER_LINE_ERR', {
|
|
|
|
error: err,
|
2019-08-12 21:26:23 +08:00
|
|
|
index: ref.index,
|
2019-06-27 17:11:22 +08:00
|
|
|
line: JSON.stringify(line),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Array.isArray(line)) {
|
|
|
|
try {
|
|
|
|
handleCommand(ref.meta, line);
|
2019-08-21 18:26:46 +08:00
|
|
|
ref.index++;
|
2019-06-28 00:21:12 +08:00
|
|
|
} catch (err2) {
|
2019-06-27 17:11:22 +08:00
|
|
|
errorHandler("METADATA_COMMAND_ERR", {
|
2019-06-28 00:21:12 +08:00
|
|
|
error: err2.stack,
|
2019-06-27 17:11:22 +08:00
|
|
|
line: line,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-08-12 21:26:23 +08:00
|
|
|
if (ref.index === 0 && typeof(line) === 'object') {
|
|
|
|
ref.index++;
|
2019-06-27 17:11:22 +08:00
|
|
|
// special case!
|
|
|
|
ref.meta = line;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
errorHandler("METADATA_HANDLER_WEIRDLINE", {
|
|
|
|
line: line,
|
2019-08-12 21:26:23 +08:00
|
|
|
index: ref.index++,
|
2019-06-27 17:11:22 +08:00
|
|
|
});
|
|
|
|
};
|
|
|
|
};
|
2019-08-28 18:40:35 +08:00
|
|
|
|