mirror of
https://github.com/standardnotes/app
synced 2026-09-13 00:45:26 -04:00
Merge branch 'feat/search-enhancements' into temp-desktop-build
This commit is contained in:
@@ -15,7 +15,7 @@ jobs:
|
||||
- name: Select Xcode 26
|
||||
uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: "26.0"
|
||||
xcode-version: "26"
|
||||
- name: Export version from package.json
|
||||
run:
|
||||
echo "PACKAGE_VERSION=$(grep '"version"' ../web/package.json | cut -d '"' -f 4 | cut -d "-" -f 1)" >> $GITHUB_ENV
|
||||
|
||||
@@ -82,7 +82,7 @@ jobs:
|
||||
- name: Select Xcode 26
|
||||
uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: "26.0"
|
||||
xcode-version: "26"
|
||||
- name: Export version from package.json
|
||||
run:
|
||||
echo "PACKAGE_VERSION=$(grep '"version"' ../web/package.json | cut -d '"' -f 4 | cut -d "-" -f 1)" >> $GITHUB_ENV
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.26.97](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2026-04-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
## [1.26.96](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-12-18)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api",
|
||||
"version": "1.26.96",
|
||||
"version": "1.26.97",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,26 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.1.588](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2026-06-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.587](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2026-05-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.586](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2026-04-29)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.585](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2026-04-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.584](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2026-04-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.583](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2026-04-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@standardnotes/clipper",
|
||||
"description": "Web clipper browser extension for Standard Notes",
|
||||
"version": "1.1.583",
|
||||
"version": "1.1.588",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build-mv2": "yarn clean && webpack --config ./webpack.config.prod.js",
|
||||
|
||||
@@ -3,6 +3,26 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.110.193](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2026-06-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.192](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2026-05-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.191](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2026-04-29)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.190](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2026-04-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.189](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2026-04-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.110.188](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2026-04-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
@@ -386,8 +386,31 @@ async function installComponent(
|
||||
}
|
||||
}
|
||||
|
||||
function validatePackageIdentifier(identifier: string) {
|
||||
if (!identifier) {
|
||||
throw new Error('Package identifier must not be empty')
|
||||
}
|
||||
|
||||
if (identifier.includes('/') || identifier.includes('\\') || identifier === '.' || identifier === '..') {
|
||||
throw new Error(`Invalid package identifier: ${identifier}`)
|
||||
}
|
||||
}
|
||||
|
||||
function assertPathWithinExtensions(absolutePath: string) {
|
||||
const extensionsRoot = path.resolve(Paths.userDataDir, Paths.extensionsDirRelative)
|
||||
const resolvedPath = path.resolve(absolutePath)
|
||||
const relativeToExtensions = path.relative(extensionsRoot, resolvedPath)
|
||||
|
||||
if (relativeToExtensions.startsWith('..') || path.isAbsolute(relativeToExtensions)) {
|
||||
throw new Error(`Path escapes extensions directory: ${absolutePath}`)
|
||||
}
|
||||
}
|
||||
|
||||
function pathsForComponent(component: Pick<Component, 'content'>) {
|
||||
const relativePath = path.join(Paths.extensionsDirRelative, component.content!.package_info.identifier)
|
||||
const identifier = component.content!.package_info.identifier
|
||||
validatePackageIdentifier(identifier)
|
||||
|
||||
const relativePath = path.join(Paths.extensionsDirRelative, identifier)
|
||||
const absolutePath = path.join(Paths.userDataDir, relativePath)
|
||||
const downloadPath = path.join(Paths.tempDir, AppName, 'downloads', component.content!.name + '.zip')
|
||||
|
||||
@@ -404,7 +427,9 @@ async function uninstallComponent(mapping: MappingFileHandler, uuid: string) {
|
||||
/** No mapping for component */
|
||||
return
|
||||
}
|
||||
const result = await new FilesManager().deleteDir(path.join(Paths.userDataDir, componentMapping.location))
|
||||
const absolutePath = path.join(Paths.userDataDir, componentMapping.location)
|
||||
assertPathWithinExtensions(absolutePath)
|
||||
const result = await new FilesManager().deleteDir(absolutePath)
|
||||
if (!result.isFailed()) {
|
||||
mapping.remove(uuid)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@standardnotes/desktop",
|
||||
"main": "./app/dist/index.js",
|
||||
"version": "3.110.188",
|
||||
"version": "3.110.193",
|
||||
"license": "AGPL-3.0",
|
||||
"author": "Standard Notes.",
|
||||
"private": true,
|
||||
|
||||
@@ -143,6 +143,71 @@ test("doesn't download anything when two install/uninstall tasks are queued", as
|
||||
t.is(downloadFileCallCount, 1)
|
||||
})
|
||||
|
||||
test('does not uninstall paths outside extensions from poisoned mapping', async (t) => {
|
||||
await packageManager.syncComponents([fakeComponent()])
|
||||
await new Promise((resolve) => setTimeout(resolve, 200))
|
||||
|
||||
const escapeDir = path.join(tmpDir.path, 'escape')
|
||||
const markerPath = path.join(escapeDir, 'marker.txt')
|
||||
await ensureDirectoryExists(escapeDir)
|
||||
await fs.writeFile(markerPath, 'keep')
|
||||
|
||||
const poisonedLocations = [path.join('Extensions', '..', 'escape'), path.join('..', 'escape')]
|
||||
|
||||
for (const location of poisonedLocations) {
|
||||
await fs.writeFile(
|
||||
path.join(contentDir, 'mapping.json'),
|
||||
JSON.stringify({
|
||||
[uuid]: { location, version },
|
||||
}),
|
||||
)
|
||||
|
||||
await packageManager.syncComponents([fakeComponent({ deleted: true })])
|
||||
await new Promise((resolve) => setTimeout(resolve, 200))
|
||||
|
||||
t.true(await fs.stat(markerPath).then(() => true), `marker preserved for location ${location}`)
|
||||
t.deepEqual(await readJSONFile(path.join(contentDir, 'mapping.json')), {
|
||||
[uuid]: { location, version },
|
||||
})
|
||||
}
|
||||
|
||||
t.true(await fs.stat(path.join(contentDir, identifier)).then(() => true))
|
||||
})
|
||||
|
||||
test('rejects path traversal in package identifier', async (t) => {
|
||||
const traversalIdentifiers = ['../escape', 'foo/../../escape', '..', '.', 'foo/bar']
|
||||
const extensionsParent = path.dirname(contentDir)
|
||||
|
||||
for (const badIdentifier of traversalIdentifiers) {
|
||||
const before = await fs.readdir(contentDir)
|
||||
const parentBefore = await fs.readdir(extensionsParent)
|
||||
|
||||
downloadFileCallCount = 0
|
||||
await packageManager.syncComponents([
|
||||
{
|
||||
...fakeComponent({ modifier: badIdentifier }),
|
||||
content: {
|
||||
...fakeComponent().content,
|
||||
name: `Bad ${badIdentifier}`,
|
||||
package_info: {
|
||||
...fakeComponent().content.package_info,
|
||||
identifier: badIdentifier,
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
await new Promise((resolve) => setTimeout(resolve, 200))
|
||||
|
||||
t.is(downloadFileCallCount, 0, `should not download for identifier ${badIdentifier}`)
|
||||
t.deepEqual(await fs.readdir(contentDir), before, `extensions dir unchanged for ${badIdentifier}`)
|
||||
t.deepEqual(
|
||||
await fs.readdir(extensionsParent),
|
||||
parentBefore,
|
||||
`no directory escape for ${badIdentifier}`,
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
test("Relies on download_url's version field to store the version number", async (t) => {
|
||||
await packageManager.syncComponents([fakeComponent()])
|
||||
await new Promise((resolve) => setTimeout(resolve, 200))
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.21.113](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2026-04-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
## [1.21.112](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2025-11-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user