chore: tech stack upgrade (#12448)

* fix(lint): make worker/frontend separation lint work on Windows

* chore: update cljs:electron-watch script to include test flag

* chore: remove dead root dependencies

* chore(deps): converge better-sqlite3 to 12.6.2 across deps packages

* chore(deps): converge fs-extra to ^11.3.0 across package roots

* fix(test): correct parameters for create-if-not-exists function

* chore(deps): converge cljs-bean to 1.9.0 across deps roots

* fix(tests): escape regex in cljs:run-test script

* chore: pin root packageManager to yarn 1.22.22

* chore(build): replace del with fs.rmSync in gulp clean

* chore(build): replace npm-run-all with npm-run-all2

* chore(security): upgrade dompurify and unify sanitizer path

* chore(observability): upgrade web sentry to 8.x

* chore: remove unused react-draggable dependencies

* chore(ci): fix windows release artifact collection

* fix(build): create static dir before gulp clean scans it

* fix: update nbb-logseq dependency to version feat-db-v33

* fix(test): move start-time initialization after clone repo

* fix(deps): update nbb dependencies and adjust test script paths to compatible with windows path delimiter

* chore(deps): remove dead meander dependency

---------

Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
This commit is contained in:
megayu
2026-03-13 13:20:49 +08:00
committed by GitHub
parent ffb82f1ccc
commit adbaf10abc
31 changed files with 334 additions and 1312 deletions

View File

@@ -302,7 +302,8 @@ jobs:
run: |
mkdir builds
mv static\out\make\squirrel.windows\x64\*.nupkg builds\Logseq-win-x64-${{ steps.ref.outputs.version }}-full.nupkg
mv static\out\make\zip\win32\x64\*.exe builds\Logseq-win-x64-${{ steps.ref.outputs.version }}.exe
mv static\out\make\squirrel.windows\x64\*.exe builds\Logseq-win-x64-${{ steps.ref.outputs.version }}.exe
mv static\out\make\zip\win32\x64\*.zip builds\Logseq-win-x64-${{ steps.ref.outputs.version }}.zip
mv static\out\make\wix\x64\Logseq.msi builds\Logseq-win-x64-${{ steps.ref.outputs.version }}.msi
mv static\out\make\squirrel.windows\x64\RELEASES builds\RELEASES
@@ -324,7 +325,7 @@ jobs:
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: logseq-win64-builds
name: logseq-win-x64-builds
path: builds
build-windows-arm64:
@@ -367,7 +368,8 @@ jobs:
run: |
mkdir builds
mv static\out\make\squirrel.windows\arm64\*.nupkg builds\Logseq-win-arm64-${{ steps.ref.outputs.version }}-full.nupkg
mv static\out\make\zip\win32\arm64\*.exe builds\Logseq-win-arm64-${{ steps.ref.outputs.version }}.exe
mv static\out\make\squirrel.windows\arm64\*.exe builds\Logseq-win-arm64-${{ steps.ref.outputs.version }}.exe
mv static\out\make\zip\win32\arm64\*.zip builds\Logseq-win-arm64-${{ steps.ref.outputs.version }}.zip
mv static\out\make\wix\arm64\Logseq.msi builds\Logseq-win-arm64-${{ steps.ref.outputs.version }}.msi
mv static\out\make\squirrel.windows\arm64\RELEASES builds\RELEASES
@@ -590,7 +592,7 @@ jobs:
- name: Download The Windows Artifact x64
uses: actions/download-artifact@v4
with:
name: logseq-win64-builds
name: logseq-win-x64-builds
path: ./
- name: Download The Windows Artifact arm64

View File

@@ -13,7 +13,7 @@
funcool/promesa {:mvn/version "11.0.678"}
medley/medley {:mvn/version "1.4.0"}
metosin/reitit-frontend {:mvn/version "0.3.10"}
cljs-bean/cljs-bean {:mvn/version "1.5.0"}
cljs-bean/cljs-bean {:mvn/version "1.9.0"}
prismatic/dommy {:mvn/version "1.1.0"}
org.clojure/core.match {:mvn/version "1.0.0"}
com.andrewmcveigh/cljs-time {:git/url "https://github.com/logseq/cljs-time" ;; fork
@@ -44,7 +44,6 @@
metosin/malli {:mvn/version "0.16.1"}
com.cognitect/transit-cljs {:mvn/version "0.8.280"}
missionary/missionary {:mvn/version "b.46"}
meander/epsilon {:mvn/version "0.0.650"}
io.github.open-spaced-repetition/cljc-fsrs {:git/sha "eeef3520df664e51c3d0ba2031ec2ba071635442"
:git/url "https://github.com/open-spaced-repetition/cljc-fsrs"}

View File

@@ -12,7 +12,7 @@
"dependencies": {
"@logseq/nbb-logseq": "github:logseq/nbb-logseq#feat-db-v33",
"@modelcontextprotocol/sdk": "^1.17.5",
"better-sqlite3": "~11.10.0",
"better-sqlite3": "^12.6.2",
"fastify": "5.3.2",
"fs-extra": "^11.3.0",
"jszip": "3.8.0",

8
deps/cli/yarn.lock vendored
View File

@@ -135,10 +135,10 @@ base64-js@^1.3.1:
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
better-sqlite3@~11.10.0:
version "11.10.0"
resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-11.10.0.tgz#2b1b14c5acd75a43fd84d12cc291ea98cef57d98"
integrity sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==
better-sqlite3@^12.6.2:
version "12.6.2"
resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-12.6.2.tgz#770649f28a62e543a360f3dfa1afe4cc944b1937"
integrity sha512-8VYKM3MjCa9WcaSAI3hzwhmyHVlH8tiGFwf0RlTsZPWJ1I5MkzjiudCo4KC4DxOaL/53A5B1sI/IbldNFDbsKA==
dependencies:
bindings "^1.5.0"
prebuild-install "^7.1.1"

2
deps/db/deps.edn vendored
View File

@@ -5,7 +5,7 @@
;; datascript/datascript {:local/root "../../../../datascript"}
datascript-transit/datascript-transit {:mvn/version "0.3.0"
:exclusions [datascript/datascript]}
cljs-bean/cljs-bean {:mvn/version "1.5.0"}
cljs-bean/cljs-bean {:mvn/version "1.9.0"}
com.cognitect/transit-cljs {:mvn/version "0.8.280"}
org.flatland/ordered {:mvn/version "1.15.11"}

View File

@@ -7,7 +7,7 @@
"fs-extra": "^11.3.0"
},
"dependencies": {
"better-sqlite3": "11.10.0"
"better-sqlite3": "^12.6.2"
},
"scripts": {
"test": "yarn nbb-logseq -cp test -m nextjournal.test-runner",

8
deps/db/yarn.lock vendored
View File

@@ -13,10 +13,10 @@ base64-js@^1.3.1:
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
better-sqlite3@11.10.0:
version "11.10.0"
resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-11.10.0.tgz#2b1b14c5acd75a43fd84d12cc291ea98cef57d98"
integrity sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==
better-sqlite3@^12.6.2:
version "12.6.2"
resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-12.6.2.tgz#770649f28a62e543a360f3dfa1afe4cc944b1937"
integrity sha512-8VYKM3MjCa9WcaSAI3hzwhmyHVlH8tiGFwf0RlTsZPWJ1I5MkzjiudCo4KC4DxOaL/53A5B1sI/IbldNFDbsKA==
dependencies:
bindings "^1.5.0"
prebuild-install "^7.1.1"

View File

@@ -4,7 +4,7 @@
{com.andrewmcveigh/cljs-time {:git/url "https://github.com/logseq/cljs-time" ;; fork
:sha "5704fbf48d3478eedcf24d458c8964b3c2fd59a9"}
funcool/promesa {:mvn/version "11.0.678"}
cljs-bean/cljs-bean {:mvn/version "1.5.0"}
cljs-bean/cljs-bean {:mvn/version "1.9.0"}
;; Any other deps should be added here and to nbb.edn
borkdude/rewrite-edn {:mvn/version "0.4.9"}

View File

@@ -4,6 +4,8 @@
{:local/root "../common"}
logseq/db
{:local/root "../db"}
logseq/outliner
{:local/root "../outliner"}
io.github.nextjournal/nbb-test-runner
{:git/sha "b379325cfa5a3306180649da5de3bf5166414e71"}
borkdude/rewrite-edn {:mvn/version "0.4.9"}

View File

@@ -4,14 +4,14 @@
"private": true,
"devDependencies": {
"@logseq/nbb-logseq": "github:logseq/nbb-logseq#feat-db-v33",
"better-sqlite3": "11.10.0"
"better-sqlite3": "^12.6.2"
},
"dependencies": {
"mldoc": "^1.5.9",
"sanitize-filename": "1.6.3"
},
"scripts": {
"test": "nbb-logseq -cp test:../outliner/src -m nextjournal.test-runner",
"test-v": "nbb-logseq -cp test:../outliner/src -m logseq.graph-parser.test-runner"
"test": "nbb-logseq -cp test -m nextjournal.test-runner",
"test-v": "nbb-logseq -cp test -m logseq.graph-parser.test-runner"
}
}

View File

@@ -285,8 +285,8 @@
(deftest-async ^:integration export-docs-graph-with-convert-all-tags
(p/let [file-graph-dir "test/resources/docs-0.10.12"
start-time (cljs.core/system-time)
_ (docs-graph-helper/clone-docs-repo-if-not-exists file-graph-dir "v0.10.12")
start-time (cljs.core/system-time)
conn (db-test/create-conn)
_ (db-pipeline/add-listener conn)
{:keys [import-state]}

View File

@@ -23,10 +23,10 @@ base64-js@^1.3.1:
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
better-sqlite3@11.10.0:
version "11.10.0"
resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-11.10.0.tgz#2b1b14c5acd75a43fd84d12cc291ea98cef57d98"
integrity sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==
better-sqlite3@^12.6.2:
version "12.6.2"
resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-12.6.2.tgz#770649f28a62e543a360f3dfa1afe4cc944b1937"
integrity sha512-8VYKM3MjCa9WcaSAI3hzwhmyHVlH8tiGFwf0RlTsZPWJ1I5MkzjiudCo4KC4DxOaL/53A5B1sI/IbldNFDbsKA==
dependencies:
bindings "^1.5.0"
prebuild-install "^7.1.1"

View File

@@ -6,7 +6,7 @@
"@logseq/nbb-logseq": "github:logseq/nbb-logseq#feat-db-v33"
},
"dependencies": {
"better-sqlite3": "11.10.0",
"better-sqlite3": "^12.6.2",
"mldoc": "^1.5.9"
},
"scripts": {

View File

@@ -23,10 +23,10 @@ base64-js@^1.3.1:
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
better-sqlite3@11.10.0:
version "11.10.0"
resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-11.10.0.tgz#2b1b14c5acd75a43fd84d12cc291ea98cef57d98"
integrity sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==
better-sqlite3@^12.6.2:
version "12.6.2"
resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-12.6.2.tgz#770649f28a62e543a360f3dfa1afe4cc944b1937"
integrity sha512-8VYKM3MjCa9WcaSAI3hzwhmyHVlH8tiGFwf0RlTsZPWJ1I5MkzjiudCo4KC4DxOaL/53A5B1sI/IbldNFDbsKA==
dependencies:
bindings "^1.5.0"
prebuild-install "^7.1.1"

View File

@@ -7,8 +7,8 @@
"mldoc": "^1.5.9"
},
"dependencies": {
"better-sqlite3": "11.10.0",
"fs-extra": "9.1.0"
"better-sqlite3": "^12.6.2",
"fs-extra": "^11.3.0"
},
"scripts": {
"test": "yarn nbb-logseq -cp test -m nextjournal.test-runner"

View File

@@ -18,20 +18,15 @@ ansi-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1"
integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==
at-least-node@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
base64-js@^1.3.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
better-sqlite3@11.10.0:
version "11.10.0"
resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-11.10.0.tgz#2b1b14c5acd75a43fd84d12cc291ea98cef57d98"
integrity sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==
better-sqlite3@^12.6.2:
version "12.6.2"
resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-12.6.2.tgz#770649f28a62e543a360f3dfa1afe4cc944b1937"
integrity sha512-8VYKM3MjCa9WcaSAI3hzwhmyHVlH8tiGFwf0RlTsZPWJ1I5MkzjiudCo4KC4DxOaL/53A5B1sI/IbldNFDbsKA==
dependencies:
bindings "^1.5.0"
prebuild-install "^7.1.1"
@@ -159,12 +154,11 @@ fs-constants@^1.0.0:
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
fs-extra@9.1.0:
version "9.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d"
integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==
fs-extra@^11.3.0:
version "11.3.4"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.3.4.tgz#ab6934eca8bcf6f7f6b82742e33591f86301d6fc"
integrity sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==
dependencies:
at-least-node "^1.0.0"
graceful-fs "^4.2.0"
jsonfile "^6.0.1"
universalify "^2.0.0"

2
deps/shui/deps.edn vendored
View File

@@ -7,4 +7,4 @@
:sha "5d672bf84ed944414b9f61eeb83808ead7be9127"}
medley/medley {:mvn/version "1.4.0"}
cljs-bean/cljs-bean {:mvn/version "1.5.0"}}}
cljs-bean/cljs-bean {:mvn/version "1.9.0"}}}

View File

@@ -4,8 +4,6 @@ const cp = require('child_process')
const exec = utils.promisify(cp.exec)
const path = require('path')
const gulp = require('gulp')
const del = require('del')
const ip = require('ip')
const replace = require('gulp-replace')
const outputPath = path.join(__dirname, 'static')
@@ -17,6 +15,13 @@ const mobileJsPath = path.join(mobilePath, 'js')
const sourcePath = path.join(__dirname, 'src/main/frontend')
const resourceFilePath = path.join(resourcesPath, '**')
const outputFilePath = path.join(outputPath, '**')
const staticCleanKeep = new Set([
'entitlements.plist',
'forge.config.js',
'node_modules',
'package.json',
'yarn.lock',
])
const css = {
watchCSS () {
@@ -54,8 +59,20 @@ const css = {
const common = {
clean () {
return del(
['./static/**/*', '!./static/node_modules'])
if (!fs.existsSync(outputPath)) {
fs.mkdirSync(outputPath, { recursive: true })
}
for (const entry of fs.readdirSync(outputPath)) {
if (staticCleanKeep.has(entry)) continue
fs.rmSync(path.join(outputPath, entry), {
recursive: true,
force: true,
maxRetries: 10,
retryDelay: 100,
})
}
return Promise.resolve()
},
syncResourceFile () {

View File

@@ -1,6 +1,6 @@
{:paths ["src" "test"]
:deps {org.clojure/clojurescript {:mvn/version "1.12.42"}
cljs-bean/cljs-bean {:mvn/version "1.5.0"}}
cljs-bean/cljs-bean {:mvn/version "1.9.0"}}
:npm-deps {"@logseq/libs" "0.2.3"}

View File

@@ -2,6 +2,7 @@
"name": "logseq",
"version": "0.0.1",
"private": true,
"packageManager": "yarn@1.22.22",
"main": "static/electron.js",
"engines": {
"node": ">=22.20.0"
@@ -20,16 +21,11 @@
"better-sqlite3": "^12.6.2",
"cross-env": "^7.0.3",
"cssnano": "^5.1.13",
"del": "^6.0.0",
"glob": "9.0.0",
"gulp": "^4.0.2",
"gulp-postcss": "^10.0.0",
"gulp-replace": "^1.1.4",
"ip": "1.1.9",
"karma": "^6.4.4",
"karma-chrome-launcher": "^3.2.0",
"karma-cljs-test": "^0.1.0",
"npm-run-all": "^4.1.5",
"npm-run-all2": "^8.0.4",
"playwright": "=1.51.0",
"postcss": "^8.4.47",
"postcss-cli": "10.0.0",
@@ -38,7 +34,6 @@
"postcss-import-ext-glob": "2.0.1",
"postcss-nested": "6.0.0",
"process": "^0.11.10",
"purgecss": "4.0.2",
"semver": "7.5.2",
"shadow-cljs": "2.28.23",
"source-map-loader": "^5.0.0",
@@ -89,13 +84,13 @@
"cljs:release-mobile": "clojure -M:cljs release mobile db-worker --config-merge \"{:output-dir \\\"./static/mobile/js\\\" :asset-path \\\"/static/mobile/js\\\" :release {:asset-path \\\"http://localhost\\\"}}\"",
"cljs:dev-watch": "clojure -M:cljs watch app db-worker inference-worker electron mobile",
"cljs:app-watch": "clojure -M:cljs watch app db-worker inference-worker",
"cljs:electron-watch": "clojure -M:cljs watch app db-worker inference-worker electron --config-merge \"{:asset-path \\\"./js\\\"}\"",
"cljs:electron-watch": "clojure -M:cljs watch app db-worker inference-worker electron test --config-merge \"{:asset-path \\\"./js\\\"}\"",
"cljs:release": "clojure -M:cljs release app db-worker inference-worker publishing electron",
"cljs:release-electron": "clojure -M:cljs release app db-worker inference-worker electron --debug && clojure -M:cljs release publishing",
"cljs:release-app": "clojure -M:cljs release app db-worker inference-worker",
"cljs:release-publishing": "clojure -M:cljs release app publishing",
"cljs:test": "clojure -M:test compile test",
"cljs:run-test": "node static/tests.js -r '^(?!logseq.db-sync.).*' -e fix-me",
"cljs:run-test": "node static/tests.js -r \"^(?!logseq.db-sync.).*\" -e fix-me",
"cljs:test-no-worker": "clojure -M:test compile test-no-worker",
"cljs:run-test-no-worker": "node static/tests-no-worker.js",
"cljs:dev-release-app": "clojure -M:cljs release app db-worker inference-worker --config-merge \"{:closure-defines {frontend.config/DEV-RELEASE true}}\"",
@@ -144,8 +139,7 @@
"@logseq/react-tweet-embed": "1.3.1-1",
"@logseq/simple-wave-record": "^0.0.3",
"@radix-ui/colors": "^0.1.8",
"@sentry/react": "^6.18.2",
"@sentry/tracing": "^6.18.2",
"@sentry/react": "^8.53.0",
"@sqlite.org/sqlite-wasm": "^3.50.3-build1",
"@tabler/icons-react": "^2.47.0",
"@tabler/icons-webfont": "^2.47.0",
@@ -156,10 +150,10 @@
"codemirror": "5.65.18",
"comlink": "^4.4.1",
"d3-force": "3.0.0",
"dompurify": "2.4.0",
"dompurify": "^3.3.3",
"emoji-mart": "^5.5.2",
"fs": "0.0.1-security",
"fs-extra": "9.1.0",
"fs-extra": "^11.3.0",
"fuse.js": "6.4.6",
"grapheme-splitter": "1.0.4",
"graphology": "0.20.0",
@@ -182,7 +176,6 @@
"prop-types": "^15.7.2",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-grid-layout": "0.16.6",
"react-intersection-observer": "^9.3.5",
"react-textarea-autosize": "8.3.3",
"react-transition-group": "4.3.0",
@@ -192,7 +185,6 @@
"send-intent": "^7.0.0",
"shepherd.js": "^9.1.0",
"tailwind-capitalize-first-letter": "^1.0.4",
"threads": "1.6.5",
"url": "^0.11.0",
"util": "^0.12.5",
"yargs-parser": "20.2.4"

View File

@@ -35,7 +35,7 @@
"electron-window-state": "5.0.3",
"extract-zip": "2.0.1",
"fastify": "5.3.2",
"fs-extra": "9.1.0",
"fs-extra": "^11.3.0",
"https-proxy-agent": "7.0.2",
"node-fetch": "2.6.7",
"open": "7.3.1",

View File

@@ -61,12 +61,20 @@
(defn- validate-workers-not-in-frontend
[]
(let [res (shell {:out :string :continue true}
"grep -r --exclude-dir=worker --exclude-dir=inference_worker" "\\[frontend.worker.*:" "src/main/frontend")
"git grep --untracked --exclude-standard"
"\\[frontend.worker.*:" "--" "src/main/frontend")
;; allow reset-file b/c it's only affects tests
allowed-exceptions #{"src/main/frontend/handler/file_based/file.cljs: [frontend.worker.file.reset :as file-reset]"}
excluded-path-prefixes ["src/main/frontend/worker/"
"src/main/frontend/inference_worker/"]
invalid-lines (when (= 0 (:exit res))
(remove #(some->> % (contains? allowed-exceptions))
(string/split-lines (:out res))))
(->> (:out res)
string/split-lines
(remove (fn [line]
(let [path (first (string/split line #":" 2))]
(or (contains? allowed-exceptions line)
(some #(string/starts-with? path %)
excluded-path-prefixes)))))))
_ (when (> (:exit res) 1) (System/exit 1))]
(if (and (= 0 (:exit res)) (seq invalid-lines))
(do (println "The following worker requires should not be in frontend namespaces:")

View File

@@ -38,7 +38,6 @@
[logseq.shui.ui :as shui]
[medley.core :as medley]
[promesa.core :as p]
[react-draggable]
[reitit.frontend.easy :as rfe]
[rum.core :as rum]))

View File

@@ -33,7 +33,6 @@
[logseq.shui.hooks :as hooks]
[logseq.shui.ui :as shui]
[promesa.core :as p]
[react-draggable]
[rum.core :as rum]))
(defonce no-matched-commands [["No matched commands" [[:editor/move-cursor-to-end]]]])

View File

@@ -25,7 +25,6 @@
[logseq.db :as ldb]
[logseq.shui.hooks :as hooks]
[logseq.shui.ui :as shui]
[react-draggable]
[reitit.frontend.easy :as rfe]
[rum.core :as rum]))

View File

@@ -3,6 +3,7 @@
[frontend.components.lazy-editor :as lazy-editor]
[frontend.handler.notification :as notification]
[frontend.handler.plugin :as plugin-handler]
[frontend.security :as security]
[frontend.ui :as ui]
[frontend.util :as util]
[goog.functions :refer [debounce]]
@@ -10,17 +11,10 @@
[logseq.shui.ui :as shui]
[rum.core :as rum]))
(defn- dom-purify
[html opts]
(try
(js-invoke js/DOMPurify "sanitize" html (bean/->js opts))
(catch js/Error e
(js/console.warn e) html)))
(rum/defc html-content
[html]
[:div.html-content.pl-1.flex-1.text-sm
{:dangerouslySetInnerHTML {:__html (dom-purify html nil)}}])
{:dangerouslySetInnerHTML {:__html (security/sanitize-html html)}}])
(rum/defc edit-settings-file
[pid {:keys [class edit-mode set-edit-mode!]}]

View File

@@ -66,5 +66,4 @@
(defn set-user!
[id]
(Sentry/configureScope (fn [scope]
(.setUser scope #js {:id id}))))
(.setUser (Sentry/getCurrentScope) #js {:id id}))

View File

@@ -1,6 +1,36 @@
(ns frontend.security
"Provide security focused fns like preventing XSS attacks"
(:require ["dompurify" :as DOMPurify]))
(:require ["dompurify" :as dompurify]))
(defn- sanitizer-instance?
[value]
(fn? (some-> value (aget "sanitize"))))
(defn- resolve-dompurify
[module]
(let [purify (or (.-default module) module)]
(cond
(sanitizer-instance? purify)
purify
(fn? purify)
(let [instance (purify js/window)]
(if (sanitizer-instance? instance)
instance
(throw (js/Error. "DOMPurify factory did not return a sanitizer instance"))))
:else
(throw (js/Error. "Unsupported DOMPurify module shape")))))
(defonce ^:private dompurify-instance (volatile! nil))
(defn- get-dompurify
([] (get-dompurify dompurify dompurify-instance))
([module cache]
(or @cache
(let [instance (resolve-dompurify module)]
(vreset! cache instance)
instance))))
(def sanitization-options (clj->js {:ADD_TAGS ["iframe"]
:ADD_ATTR ["is"]
@@ -8,4 +38,4 @@
(defn sanitize-html
[html]
(.sanitize DOMPurify html sanitization-options))
(js-invoke (get-dompurify) "sanitize" html sanitization-options))

View File

@@ -17,7 +17,7 @@
(->
(p/do!
(fs/create-if-not-exists nil dir some-file "NEW")
(fs/create-if-not-exists nil nil some-file "NEW")
(is (fs-node/existsSync some-file)
"something.txt created correctly")
(is (= "NEW"
@@ -36,7 +36,7 @@
(->
(p/do!
(fs/create-if-not-exists nil dir some-file "NEW")
(fs/create-if-not-exists nil nil some-file "NEW")
(is (= "OLD" (str (fs-node/readFileSync some-file)))
"something.txt has not been touched and old content still exists"))

View File

@@ -0,0 +1,47 @@
(ns frontend.security-test
(:require [cljs.test :refer [deftest is testing]]
[frontend.security :as security]))
(deftest sanitize-html-uses-logseq-sanitization-policy
(testing "sanitize-html delegates to DOMPurify with the repository's supported plugin policy"
(let [called (atom nil)
html "<p onclick=\"alert('x')\">safe</p><iframe src=\"logseq://plugin/frame\" is=\"plugin-frame\"></iframe><script>alert('x')</script>"
fake-purify #js {:sanitize (fn [input opts]
(reset! called {:input input
:opts (js->clj opts)})
"<p>safe</p><iframe src=\"logseq://plugin/frame\" is=\"plugin-frame\"></iframe>")}]
(with-redefs [security/get-dompurify (fn [] fake-purify)]
(is (= "<p>safe</p><iframe src=\"logseq://plugin/frame\" is=\"plugin-frame\"></iframe>"
(security/sanitize-html html)))
(is (= html (:input @called)))
(is (= ["iframe"] (get-in @called [:opts "ADD_TAGS"])))
(is (= ["is"] (get-in @called [:opts "ADD_ATTR"])))
(is (= true (get-in @called [:opts "ALLOW_UNKNOWN_PROTOCOLS"])))))))
(deftest resolve-dompurify-fails-fast-on-unsupported-shapes
(testing "unsupported module shapes fail explicitly instead of falling through to a later sanitize call"
(let [bad-module-error (try
(#'security/resolve-dompurify #js {})
nil
(catch js/Error error
error))
bad-factory-error (try
(#'security/resolve-dompurify (fn [_] #js {}))
nil
(catch js/Error error
error))]
(is (= "Unsupported DOMPurify module shape" (.-message bad-module-error)))
(is (= "DOMPurify factory did not return a sanitizer instance"
(.-message bad-factory-error))))))
(deftest get-dompurify-caches-the-resolved-instance
(testing "the DOMPurify instance is resolved once and then reused"
(let [calls (atom 0)
cache (volatile! nil)
fake-instance #js {:sanitize (fn [_ _] "<p>safe</p>")}]
(with-redefs [security/resolve-dompurify (fn [_]
(swap! calls inc)
fake-instance)]
(is (identical? fake-instance (#'security/get-dompurify #js {} cache)))
(is (identical? fake-instance (#'security/get-dompurify #js {} cache)))
(is (= 1 @calls))))))

1387
yarn.lock

File diff suppressed because it is too large Load Diff