Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/test-and-publish-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@v6.0.2
- uses: actions/setup-node@v6.3.0
with:
node-version: 20
node-version: 24
- name: 🔧 Install
run: |
yarn
Expand All @@ -28,7 +28,7 @@ jobs:
yarn build-storybook
- name: 🚀 Deploy Storybook
if: github.ref == 'refs/heads/main'
uses: JamesIves/github-pages-deploy-action@v4.3.3
uses: JamesIves/github-pages-deploy-action@v4.6.8
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
branch: gh-pages # The branch the action should deploy to.
Expand Down
5 changes: 1 addition & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,5 @@
"packages/*"
],
"customElements": "custom-elements.json",
"sideEffects": false,
"dependencies": {
"rimraff": "0.0.1-security"
}
"sideEffects": false
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ export const calculateConservation = (

// Note that the line `const f = ${calculateConservation.toString()};` allows us to keep that
// function's source code in TypeScript while also being transpiled into JavaScript.
//
// SECURITY: This pattern constructs code-as-string for a Blob-based Web Worker.
// The Worker ONLY receives bioinformatics sequence data from the same origin.
// Do NOT interpolate any untrusted or user-supplied data into this template string.
// If this pattern needs to change, consider migrating to a standard Worker with a
// bundled module file to restore TypeScript type safety and avoid code injection risks.
const conservationInlineWorkerString = `
self.addEventListener('message', (e) => {
if (self.previous !== e.data) {
Expand Down
3 changes: 2 additions & 1 deletion packages/nightingale-scrollbox/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
},
"sideEffects": false,
"dependencies": {
"@nightingale-elements/nightingale-new-core": "^5.6.0"
"@nightingale-elements/nightingale-new-core": "^5.6.0",
"dompurify": "^3.0.0"
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import NightingaleElement from "@nightingale-elements/nightingale-new-core";
import { customElement, property } from "lit/decorators.js";
import DOMPurify from "dompurify";
import { NightingaleScrollbox } from "./nightingale-scrollbox";


Expand Down Expand Up @@ -85,7 +86,7 @@ export class NightingaleScrollboxItem<TData> extends NightingaleElement {

private setContent(content: string | null | undefined) {
if (content === undefined || content === null) return;
this.innerHTML = content;
this.innerHTML = DOMPurify.sanitize(content);
}

/** Set or remove "onRegister" callback function. Also run this callback function if the item is already registered (i.e. in "new", "visible", or "hidden" state). */
Expand Down
1 change: 1 addition & 0 deletions packages/nightingale-structure/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"dependencies": {
"@nightingale-elements/nightingale-new-core": "^5.6.0",
"d3": "7.9.0",
"dompurify": "^3.0.0",
"molstar": "3.44.0"
}
}
27 changes: 14 additions & 13 deletions packages/nightingale-structure/src/nightingale-structure.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable class-methods-use-this */
import { html, nothing } from "lit";
import { property, state } from "lit/decorators.js";
import DOMPurify from "dompurify";

import NightingaleElement, {
withHighlight,
Expand Down Expand Up @@ -93,7 +94,7 @@ const alphaFoldMappingUrl = "https://alphafold.ebi.ac.uk/api/prediction/";

@customElementOnce("nightingale-structure")
class NightingaleStructure extends withManager(
withHighlight(NightingaleElement)
withHighlight(NightingaleElement),
) {
@property({ type: String })
"protein-accession"?: string;
Expand Down Expand Up @@ -191,7 +192,7 @@ class NightingaleStructure extends withManager(
<span>${this.message?.title}</span>:
<span
class="structure-viewer-message-content"
.innerHTML=${this.message?.content}
.innerHTML=${DOMPurify.sanitize(this.message?.content ?? "")}
></span>
<button
type="button"
Expand All @@ -212,7 +213,7 @@ class NightingaleStructure extends withManager(
getStructureViewer(
structureViewerDiv,
this.updateHighlight,
this["color-theme"]
this["color-theme"],
).then((structureViewer) => {
this.#structureViewer = structureViewer;
// Remove initial "#" and possible trailing opacity value
Expand All @@ -224,7 +225,7 @@ class NightingaleStructure extends withManager(
}

protected override updated(
changedProperties: Map<PropertyKey, unknown>
changedProperties: Map<PropertyKey, unknown>,
): void {
if (
changedProperties.has("structure-id") ||
Expand Down Expand Up @@ -285,7 +286,7 @@ class NightingaleStructure extends withManager(
async selectMolecule(): Promise<void> {
if (this["structure-id"] && this["model-url"]) {
console.error(
"Structure ID and Model URL both are present. Provide only one that you would want to take precedence"
"Structure ID and Model URL both are present. Provide only one that you would want to take precedence",
);
return;
}
Expand All @@ -300,7 +301,7 @@ class NightingaleStructure extends withManager(
if (this.isAF()) {
const afPredictions = await this.loadAFEntry(this["protein-accession"]);
const afInfo = afPredictions.find(
(prediction) => prediction.modelEntityId === this["structure-id"]
(prediction) => prediction.modelEntityId === this["structure-id"],
);
// Note: maybe use bcif instead of cif, but I have issues loading it atm
if (afInfo?.cifUrl) {
Expand All @@ -318,12 +319,12 @@ class NightingaleStructure extends withManager(
await this.#structureViewer?.loadFromUrl(
`${this["custom-download-url"]}${this[
"structure-id"
].toLowerCase()}.cif`
].toLowerCase()}.cif`,
);
this.clearMessage();
} else {
await this.#structureViewer?.loadPdb(
this["structure-id"].toLowerCase()
this["structure-id"].toLowerCase(),
);
this.clearMessage();
}
Expand Down Expand Up @@ -360,7 +361,7 @@ class NightingaleStructure extends withManager(
}

updateHighlight(
sequencePositions: { chain: string; position: number }[]
sequencePositions: { chain: string; position: number }[],
): void {
// sequencePositions assumed to be in PDB coordinate space
if (
Expand All @@ -386,8 +387,8 @@ class NightingaleStructure extends withManager(
pos.position,
pos.position,
"PDB_UP",
this.selectedMolecule?.mappings
).filter((t) => t.chain === pos.chain)
this.selectedMolecule?.mappings,
).filter((t) => t.chain === pos.chain),
)
.filter(Boolean);
} catch (error) {
Expand Down Expand Up @@ -417,7 +418,7 @@ class NightingaleStructure extends withManager(
})
.join("");

this.showMessage(`${this["structure-id"]}`, tooltip);
this.showMessage(this["structure-id"] || "", tooltip);
const event = new CustomEvent("change", {
detail: {
highlight,
Expand Down Expand Up @@ -448,7 +449,7 @@ class NightingaleStructure extends withManager(
start,
end,
"UP_PDB",
this.selectedMolecule?.mappings
this.selectedMolecule?.mappings,
);
})
.filter(Boolean);
Expand Down
45 changes: 36 additions & 9 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4214,7 +4214,7 @@
resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz#cb6e2a691b70cb177c6e3ae9c1d2e8b2ea8cd304"
integrity sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==

"@types/trusted-types@^2.0.2":
"@types/trusted-types@^2.0.2", "@types/trusted-types@^2.0.7":
version "2.0.7"
resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11"
integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==
Expand Down Expand Up @@ -7702,6 +7702,13 @@ domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1:
dependencies:
domelementtype "^2.2.0"

dompurify@^3.0.0:
version "3.3.3"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.3.3.tgz#680cae8af3e61320ddf3666a3bc843f7b291b2b6"
integrity sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==
optionalDependencies:
"@types/trusted-types" "^2.0.7"

domutils@^2.5.2, domutils@^2.8.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
Expand Down Expand Up @@ -15024,11 +15031,6 @@ rimraf@^4.4.1:
dependencies:
glob "^9.2.0"

rimraff@0.0.1-security:
version "0.0.1-security"
resolved "https://registry.yarnpkg.com/rimraff/-/rimraff-0.0.1-security.tgz#5454c7f9c8df1fedabf107af7ef0ef5bb0a05d09"
integrity sha512-fW4+yD5XH1dFCJmbp3OK624b8yQ6c7SvyLDzyAT+UIOSuUZ+toClQCTw8ZV/ik8UqPln8dwwGGbCSE8UkicqVQ==

ripemd160@^2.0.0, ripemd160@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
Expand Down Expand Up @@ -15854,7 +15856,16 @@ string-length@^4.0.1:
char-regex "^1.0.2"
strip-ansi "^6.0.0"

"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3:
"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"

"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
Expand Down Expand Up @@ -15965,7 +15976,7 @@ stringify-entities@^4.0.0:
character-entities-html4 "^2.0.0"
character-entities-legacy "^3.0.0"

"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
Expand All @@ -15979,6 +15990,13 @@ strip-ansi@^3.0.1:
dependencies:
ansi-regex "^2.0.0"

strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"

strip-ansi@^7.0.1:
version "7.1.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
Expand Down Expand Up @@ -17558,7 +17576,7 @@ worker-rpc@^0.1.0:
dependencies:
microevent.ts "~0.1.1"

"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
Expand All @@ -17576,6 +17594,15 @@ wrap-ansi@^6.0.1:
string-width "^4.1.0"
strip-ansi "^6.0.0"

wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"

wrap-ansi@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
Expand Down