Files

163 lines
3.3 KiB
JavaScript

import { devLogger } from "../utils/logger.js";
export const ATTACHMENT_KIND = 15;
const HEX_64_REGEX = /^[0-9a-f]{64}$/i;
const TAG_NAMES = Object.freeze({
hash: "x",
url: "url",
name: "name",
type: "type",
size: "size",
key: "k",
});
function normalizeTagValue(value) {
if (typeof value !== "string") {
if (value === undefined || value === null) {
return "";
}
return String(value);
}
return value.trim();
}
function normalizeHash(value) {
const normalized = normalizeTagValue(value).toLowerCase();
if (!normalized) {
return "";
}
return HEX_64_REGEX.test(normalized) ? normalized : "";
}
function normalizeNumber(value) {
const numeric = Number(value);
if (!Number.isFinite(numeric) || numeric < 0) {
return null;
}
return Math.floor(numeric);
}
export function parseAttachmentTags(tags) {
if (!Array.isArray(tags)) {
return null;
}
const fields = {
x: "",
url: "",
name: "",
type: "",
size: null,
key: "",
};
tags.forEach((tag) => {
if (!Array.isArray(tag) || tag.length < 2) {
return;
}
const name = normalizeTagValue(tag[0]).toLowerCase();
const value = normalizeTagValue(tag[1]);
switch (name) {
case TAG_NAMES.hash:
fields.x = normalizeHash(value);
break;
case TAG_NAMES.url:
fields.url = value;
break;
case TAG_NAMES.name:
fields.name = value;
break;
case TAG_NAMES.type:
fields.type = value;
break;
case TAG_NAMES.size:
fields.size = normalizeNumber(value);
break;
case TAG_NAMES.key:
fields.key = value;
break;
default:
break;
}
});
if (!fields.x && !fields.url) {
return null;
}
return {
x: fields.x,
url: fields.url,
name: fields.name,
type: fields.type,
size: fields.size,
key: fields.key,
encrypted: Boolean(fields.key),
};
}
export function extractAttachmentsFromMessage(message) {
if (!message || typeof message !== "object") {
return [];
}
const event =
(message.message && typeof message.message === "object"
? message.message
: null) ||
(message.event && typeof message.event === "object" ? message.event : null);
if (!event || Number(event.kind) !== ATTACHMENT_KIND) {
return [];
}
const attachment = parseAttachmentTags(event.tags);
if (!attachment) {
devLogger.warn("[attachments] Attachment event missing tags.");
return [];
}
return [attachment];
}
export function formatAttachmentSize(bytes) {
if (!Number.isFinite(bytes)) {
return "";
}
const units = ["B", "KB", "MB", "GB"];
let size = Math.max(bytes, 0);
let unitIndex = 0;
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024;
unitIndex += 1;
}
const rounded = size >= 10 || unitIndex === 0 ? Math.round(size) : size.toFixed(1);
return `${rounded} ${units[unitIndex]}`;
}
export function describeAttachment(attachment) {
if (!attachment || typeof attachment !== "object") {
return "Attachment";
}
const name = typeof attachment.name === "string" ? attachment.name.trim() : "";
if (name) {
return `Attachment: ${name}`;
}
if (attachment.type) {
return `Attachment (${attachment.type})`;
}
return "Attachment";
}
export { TAG_NAMES as ATTACHMENT_TAG_NAMES };