286 lines
6.5 KiB
JavaScript
286 lines
6.5 KiB
JavaScript
/* eslint-disable callback-return */
|
|
/**
|
|
* @requires packet/all_packets
|
|
* @requires packet/packet
|
|
* @requires config
|
|
* @requires enums
|
|
* @requires util
|
|
*/
|
|
|
|
import * as packets from './all_packets';
|
|
import packetParser from './packet';
|
|
import config from '../config';
|
|
import enums from '../enums';
|
|
import util from '../util';
|
|
|
|
/**
|
|
* This class represents a list of openpgp packets.
|
|
* Take care when iterating over it - the packets themselves
|
|
* are stored as numerical indices.
|
|
* @memberof module:packet
|
|
* @constructor
|
|
*/
|
|
function List() {
|
|
/**
|
|
* The number of packets contained within the list.
|
|
* @readonly
|
|
* @type {Integer}
|
|
*/
|
|
this.length = 0;
|
|
}
|
|
|
|
/**
|
|
* Reads a stream of binary data and interprents it as a list of packets.
|
|
* @param {Uint8Array} A Uint8Array of bytes.
|
|
*/
|
|
List.prototype.read = function (bytes) {
|
|
let i = 0;
|
|
|
|
while (i < bytes.length) {
|
|
const parsed = packetParser.read(bytes, i, bytes.length - i);
|
|
i = parsed.offset;
|
|
|
|
let pushed = false;
|
|
try {
|
|
const tag = enums.read(enums.packet, parsed.tag);
|
|
const packet = packets.newPacketFromTag(tag);
|
|
this.push(packet);
|
|
pushed = true;
|
|
packet.read(parsed.packet);
|
|
} catch (e) {
|
|
if (!config.tolerant ||
|
|
parsed.tag === enums.packet.symmetricallyEncrypted ||
|
|
parsed.tag === enums.packet.literal ||
|
|
parsed.tag === enums.packet.compressed) {
|
|
throw e;
|
|
}
|
|
util.print_debug_error(e);
|
|
if (pushed) {
|
|
this.pop(); // drop unsupported packet
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Creates a binary representation of openpgp objects contained within the
|
|
* class instance.
|
|
* @returns {Uint8Array} A Uint8Array containing valid openpgp packets.
|
|
*/
|
|
List.prototype.write = function () {
|
|
const arr = [];
|
|
|
|
for (let i = 0; i < this.length; i++) {
|
|
const packetbytes = this[i].write();
|
|
arr.push(packetParser.writeHeader(this[i].tag, packetbytes.length));
|
|
arr.push(packetbytes);
|
|
}
|
|
|
|
return util.concatUint8Array(arr);
|
|
};
|
|
|
|
/**
|
|
* Adds a packet to the list. This is the only supported method of doing so;
|
|
* writing to packetlist[i] directly will result in an error.
|
|
* @param {Object} packet Packet to push
|
|
*/
|
|
List.prototype.push = function (packet) {
|
|
if (!packet) {
|
|
return;
|
|
}
|
|
|
|
packet.packets = packet.packets || new List();
|
|
|
|
this[this.length] = packet;
|
|
this.length++;
|
|
};
|
|
|
|
/**
|
|
* Remove a packet from the list and return it.
|
|
* @returns {Object} The packet that was removed
|
|
*/
|
|
List.prototype.pop = function() {
|
|
if (this.length === 0) {
|
|
return;
|
|
}
|
|
|
|
const packet = this[this.length - 1];
|
|
delete this[this.length - 1];
|
|
this.length--;
|
|
|
|
return packet;
|
|
};
|
|
|
|
/**
|
|
* Creates a new PacketList with all packets that pass the test implemented by the provided function.
|
|
*/
|
|
List.prototype.filter = function (callback) {
|
|
const filtered = new List();
|
|
|
|
for (let i = 0; i < this.length; i++) {
|
|
if (callback(this[i], i, this)) {
|
|
filtered.push(this[i]);
|
|
}
|
|
}
|
|
|
|
return filtered;
|
|
};
|
|
|
|
/**
|
|
* Creates a new PacketList with all packets from the given types
|
|
*/
|
|
List.prototype.filterByTag = function (...args) {
|
|
const filtered = new List();
|
|
const that = this;
|
|
|
|
const handle = tag => packetType => tag === packetType;
|
|
|
|
for (let i = 0; i < this.length; i++) {
|
|
if (args.some(handle(that[i].tag))) {
|
|
filtered.push(this[i]);
|
|
}
|
|
}
|
|
|
|
return filtered;
|
|
};
|
|
|
|
/**
|
|
* Executes the provided callback once for each element
|
|
*/
|
|
List.prototype.forEach = function (callback) {
|
|
for (let i = 0; i < this.length; i++) {
|
|
callback(this[i], i, this);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Returns an array containing return values of callback
|
|
* on each element
|
|
*/
|
|
List.prototype.map = function (callback) {
|
|
const packetArray = [];
|
|
|
|
for (let i = 0; i < this.length; i++) {
|
|
packetArray.push(callback(this[i], i, this));
|
|
}
|
|
|
|
return packetArray;
|
|
};
|
|
|
|
/**
|
|
* Executes the callback function once for each element
|
|
* until it finds one where callback returns a truthy value
|
|
* @param {Function} callback
|
|
* @returns {Promise<Boolean>}
|
|
* @async
|
|
*/
|
|
List.prototype.some = async function (callback) {
|
|
for (let i = 0; i < this.length; i++) {
|
|
// eslint-disable-next-line no-await-in-loop
|
|
if (await callback(this[i], i, this)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
/**
|
|
* Executes the callback function once for each element,
|
|
* returns true if all callbacks returns a truthy value
|
|
*/
|
|
List.prototype.every = function (callback) {
|
|
for (let i = 0; i < this.length; i++) {
|
|
if (!callback(this[i], i, this)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* Traverses packet tree and returns first matching packet
|
|
* @param {module:enums.packet} type The packet type
|
|
* @returns {module:packet/packet|null}
|
|
*/
|
|
List.prototype.findPacket = function (type) {
|
|
const packetlist = this.filterByTag(type);
|
|
if (packetlist.length) {
|
|
return packetlist[0];
|
|
}
|
|
let found = null;
|
|
for (let i = 0; i < this.length; i++) {
|
|
if (this[i].packets.length) {
|
|
found = this[i].packets.findPacket(type);
|
|
if (found) {
|
|
return found;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* Returns array of found indices by tag
|
|
*/
|
|
List.prototype.indexOfTag = function (...args) {
|
|
const tagIndex = [];
|
|
const that = this;
|
|
|
|
const handle = tag => packetType => tag === packetType;
|
|
|
|
for (let i = 0; i < this.length; i++) {
|
|
if (args.some(handle(that[i].tag))) {
|
|
tagIndex.push(i);
|
|
}
|
|
}
|
|
return tagIndex;
|
|
};
|
|
|
|
/**
|
|
* Returns slice of packetlist
|
|
*/
|
|
List.prototype.slice = function (begin, end) {
|
|
if (!end) {
|
|
end = this.length;
|
|
}
|
|
const part = new List();
|
|
for (let i = begin; i < end; i++) {
|
|
part.push(this[i]);
|
|
}
|
|
return part;
|
|
};
|
|
|
|
/**
|
|
* Concatenates packetlist or array of packets
|
|
*/
|
|
List.prototype.concat = function (packetlist) {
|
|
if (packetlist) {
|
|
for (let i = 0; i < packetlist.length; i++) {
|
|
this.push(packetlist[i]);
|
|
}
|
|
}
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Allocate a new packetlist from structured packetlist clone
|
|
* See {@link https://w3c.github.io/html/infrastructure.html#safe-passing-of-structured-data}
|
|
* @param {Object} packetClone packetlist clone
|
|
* @returns {Object} new packetlist object with data from packetlist clone
|
|
*/
|
|
List.fromStructuredClone = function(packetlistClone) {
|
|
const packetlist = new List();
|
|
for (let i = 0; i < packetlistClone.length; i++) {
|
|
packetlist.push(packets.fromStructuredClone(packetlistClone[i]));
|
|
if (packetlist[i].packets.length !== 0) {
|
|
packetlist[i].packets = this.fromStructuredClone(packetlist[i].packets);
|
|
} else {
|
|
packetlist[i].packets = new List();
|
|
}
|
|
}
|
|
return packetlist;
|
|
};
|
|
|
|
export default List;
|