This commit is contained in:
Sam Hoffman
2026-01-18 19:36:29 -05:00
parent b05827712b
commit a1f19b9464
4 changed files with 156 additions and 4 deletions

View File

@@ -11,7 +11,9 @@
"@fontsource/roboto": "^5.2.9", "@fontsource/roboto": "^5.2.9",
"@mdi/font": "^7.4.47", "@mdi/font": "^7.4.47",
"buffer": "^6.0.3", "buffer": "^6.0.3",
"dompurify": "^3.3.1",
"irc-framework": "^4.14.0", "irc-framework": "^4.14.0",
"markdown-it": "^14.1.0",
"pinia": "^3.0.4", "pinia": "^3.0.4",
"vite-plugin-node-polyfills": "^0.25.0", "vite-plugin-node-polyfills": "^0.25.0",
"vue": "^3.2.37", "vue": "^3.2.37",
@@ -20,6 +22,8 @@
"devDependencies": { "devDependencies": {
"@babel/types": "^7.18.10", "@babel/types": "^7.18.10",
"@tsconfig/node22": "^22.0.5", "@tsconfig/node22": "^22.0.5",
"@types/dompurify": "^3.0.5",
"@types/markdown-it": "^14.1.2",
"@vitejs/plugin-vue": "^6.0.3", "@vitejs/plugin-vue": "^6.0.3",
"@vue/tsconfig": "^0.8.1", "@vue/tsconfig": "^0.8.1",
"eslint": "^9.39.2", "eslint": "^9.39.2",
@@ -1569,6 +1573,16 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/dompurify": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz",
"integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/trusted-types": "*"
}
},
"node_modules/@types/estree": { "node_modules/@types/estree": {
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
@@ -1583,6 +1597,38 @@
"license": "MIT", "license": "MIT",
"peer": true "peer": true
}, },
"node_modules/@types/linkify-it": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
"integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/markdown-it": {
"version": "14.1.2",
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
"integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/linkify-it": "^5",
"@types/mdurl": "^2"
}
},
"node_modules/@types/mdurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
"integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/trusted-types": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
"devOptional": true,
"license": "MIT"
},
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.53.0", "version": "8.53.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.53.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.53.0.tgz",
@@ -2127,7 +2173,6 @@
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true,
"license": "Python-2.0" "license": "Python-2.0"
}, },
"node_modules/asn1.js": { "node_modules/asn1.js": {
@@ -2999,6 +3044,15 @@
"url": "https://bevry.me/fund" "url": "https://bevry.me/fund"
} }
}, },
"node_modules/dompurify": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz",
"integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==",
"license": "(MPL-2.0 OR Apache-2.0)",
"optionalDependencies": {
"@types/trusted-types": "^2.0.7"
}
},
"node_modules/dunder-proto": { "node_modules/dunder-proto": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
@@ -4542,6 +4596,15 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/linkify-it": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
"license": "MIT",
"dependencies": {
"uc.micro": "^2.0.0"
}
},
"node_modules/local-pkg": { "node_modules/local-pkg": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz",
@@ -4597,6 +4660,35 @@
"@jridgewell/sourcemap-codec": "^1.5.5" "@jridgewell/sourcemap-codec": "^1.5.5"
} }
}, },
"node_modules/markdown-it": {
"version": "14.1.0",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
"integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1",
"entities": "^4.4.0",
"linkify-it": "^5.0.0",
"mdurl": "^2.0.0",
"punycode.js": "^2.3.1",
"uc.micro": "^2.1.0"
},
"bin": {
"markdown-it": "bin/markdown-it.mjs"
}
},
"node_modules/markdown-it/node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/math-intrinsics": { "node_modules/math-intrinsics": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@@ -4617,6 +4709,12 @@
"safe-buffer": "^5.1.2" "safe-buffer": "^5.1.2"
} }
}, },
"node_modules/mdurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
"license": "MIT"
},
"node_modules/middleware-handler": { "node_modules/middleware-handler": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/middleware-handler/-/middleware-handler-0.2.0.tgz", "resolved": "https://registry.npmjs.org/middleware-handler/-/middleware-handler-0.2.0.tgz",
@@ -5308,6 +5406,15 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/punycode.js": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/qs": { "node_modules/qs": {
"version": "6.14.1", "version": "6.14.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
@@ -6535,6 +6642,12 @@
"typescript": ">=4.8.4 <6.0.0" "typescript": ">=4.8.4 <6.0.0"
} }
}, },
"node_modules/uc.micro": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
"license": "MIT"
},
"node_modules/ufo": { "node_modules/ufo": {
"version": "1.6.3", "version": "1.6.3",
"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz",

View File

@@ -12,7 +12,9 @@
"@fontsource/roboto": "^5.2.9", "@fontsource/roboto": "^5.2.9",
"@mdi/font": "^7.4.47", "@mdi/font": "^7.4.47",
"buffer": "^6.0.3", "buffer": "^6.0.3",
"dompurify": "^3.3.1",
"irc-framework": "^4.14.0", "irc-framework": "^4.14.0",
"markdown-it": "^14.1.0",
"pinia": "^3.0.4", "pinia": "^3.0.4",
"vite-plugin-node-polyfills": "^0.25.0", "vite-plugin-node-polyfills": "^0.25.0",
"vue": "^3.2.37", "vue": "^3.2.37",
@@ -21,6 +23,8 @@
"devDependencies": { "devDependencies": {
"@babel/types": "^7.18.10", "@babel/types": "^7.18.10",
"@tsconfig/node22": "^22.0.5", "@tsconfig/node22": "^22.0.5",
"@types/dompurify": "^3.0.5",
"@types/markdown-it": "^14.1.2",
"@vitejs/plugin-vue": "^6.0.3", "@vitejs/plugin-vue": "^6.0.3",
"@vue/tsconfig": "^0.8.1", "@vue/tsconfig": "^0.8.1",
"eslint": "^9.39.2", "eslint": "^9.39.2",

View File

@@ -61,9 +61,8 @@ watch(
><v-icon class="mr-2">mdi-eye</v-icon>Only visible to you ><v-icon class="mr-2">mdi-eye</v-icon>Only visible to you
</v-chip> </v-chip>
</v-list-item-title> </v-list-item-title>
<pre style="white-space: pre">{{ msg.message }}</pre> <div v-html="msg.message" /> </v-list-item
</v-list-item></template ></template>
>
</v-virtual-scroll> </v-virtual-scroll>
</div> </div>
</v-sheet> </v-sheet>

View File

@@ -4,6 +4,8 @@ import { Client } from "irc-framework";
import { useBufferStore } from "./bufferStore"; import { useBufferStore } from "./bufferStore";
import { ref } from "vue"; import { ref } from "vue";
import { useAccountStore } from "./accountStore"; import { useAccountStore } from "./accountStore";
import MarkdownIt from "markdown-it";
import DOMPurify from "dompurify";
export type HookFunction = (event: any) => HookStatus; export type HookFunction = (event: any) => HookStatus;
@@ -19,6 +21,39 @@ interface Batch {
params: string[]; params: string[];
} }
const md = new MarkdownIt({
html: false,
linkify: true,
typographer: true,
});
function renderMessage(msgIn: string) {
if (!msgIn) return "";
const dirty = md.render(msgIn);
return DOMPurify.sanitize(dirty, {
ALLOWED_TAGS: [
"li",
"ul",
"ol",
"b",
"i",
"em",
"strong",
"a",
"code",
"pre",
"br",
"p",
"h1",
"h2",
"h3",
"h4",
"h5",
],
ALLOWED_ATTR: ["href", "target", "class"],
});
}
export const useIRCStore = defineStore("ircStore", () => { export const useIRCStore = defineStore("ircStore", () => {
const bufferStore = useBufferStore(); const bufferStore = useBufferStore();
const accountStore = useAccountStore(); const accountStore = useAccountStore();
@@ -289,6 +324,7 @@ export const useIRCStore = defineStore("ircStore", () => {
}); });
} }
message.message = renderMessage(message.message);
buffer.messages.push(message); buffer.messages.push(message);
if ( if (