Compare commits

..
Author SHA1 Message Date
Lotus CIandClaude Opus 5.5 2ac764cd45 fix(profile): private notes say they are stored unencrypted on the homeserver (#329)
CI / Build & Quality Checks (pull_request) Successful in 2m6s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 7s
CI / Playwright smoke (e2e) (pull_request) Successful in 13m48s
"Notes only visible to you" overstated it: notes live in plain account
data that homeserver admins can read. Say so under the note box (and
link it as the box's description): "Only you can see this in Lotus Chat.
It's stored on your homeserver and isn't end-to-end encrypted."

Fixes #329

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-19 00:28:39 -04:00
4 changed files with 19 additions and 41 deletions
-3
View File
@@ -12,9 +12,6 @@ regexes = [
'''https?://matrix\.lotusguild\.org''',
'''https?://code\.lotusguild\.org/api/packages/LotusGuild/npm/''',
'''matrix\.lotusguild\.org''',
# Lotus Chat desktop updater's minisign PUBLIC key (published in the
# cinny-desktop README); utils/updateErrors.ts verifies Linux downloads with it.
'''RWRZZdyii05/NUcz337A5SAbiZK\+NPVDWuiL2mM5Jk1p/LfRmNfiZ/6l''',
]
paths = [
'''config\.json''',
@@ -286,10 +286,11 @@ function UserPrivateNotes({ userId }: { userId: string }) {
</Box>
<textarea
aria-label="Private note about this user"
aria-describedby="private-note-storage"
value={draft}
onChange={handleChange}
maxLength={USER_NOTE_MAX_LENGTH}
placeholder="Notes only visible to you…"
placeholder="Add a private note…"
rows={3}
style={{
width: '100%',
@@ -305,6 +306,11 @@ function UserPrivateNotes({ userId }: { userId: string }) {
outline: 'none',
}}
/>
{/* [Gitea #329] Account data isn't end-to-end encrypted: say so. */}
<Text id="private-note-storage" size="T200" priority="300">
Only you can see this in Lotus Chat. It&apos;s stored on your homeserver and isn&apos;t
end-to-end encrypted.
</Text>
</Box>
);
}
+3 -13
View File
@@ -69,23 +69,13 @@ test('install kinds: anything unknown keeps the in-app updater', async () => {
test('package installs get their package manager’s command, not an Install button', async () => {
const { packageUpdateHelp, isPackageManagedError } = await import('./updateErrors');
const pacman = packageUpdateHelp('pacman')!;
// [cinny-desktop #36] signature, then checksum, then install, in that order;
// a local `pacman -U ./file` (not `<url>`, which also wants `<url>.sig`).
const steps = pacman.command!.split(' && ');
assert.equal(steps[0], 'cd "$(mktemp -d)"');
assert.match(
steps[1],
/-fLO \S+\/LotusChat-x86_64\.pkg\.tar\.zst -fLO \S+\/SHA256SUMS\.txt -fLO \S+\/SHA256SUMS\.txt\.minisig$/,
);
// Not `pacman -U <url>`: that also wants `<url>.sig`, which we don't publish.
assert.equal(
steps[2],
'minisign -Vm SHA256SUMS.txt -P RWRZZdyii05/NUcz337A5SAbiZK+NPVDWuiL2mM5Jk1p/LfRmNfiZ/6l',
pacman.command,
'curl -LO https://code.lotusguild.org/LotusGuild/cinny-desktop/releases/download/latest/LotusChat-x86_64.pkg.tar.zst && sudo pacman -U ./LotusChat-x86_64.pkg.tar.zst',
);
assert.equal(steps[3], 'sha256sum -c --ignore-missing SHA256SUMS.txt');
assert.equal(steps[4], 'sudo pacman -U ./LotusChat-x86_64.pkg.tar.zst');
assert.match(pacman.url, /LotusChat-x86_64\.pkg\.tar\.zst$/);
const deb = packageUpdateHelp('deb')!;
assert.match(deb.command!, /minisign -Vm SHA256SUMS\.txt/);
assert.match(deb.command!, /sudo apt install \.\/LotusChat-x86_64\.deb$/);
assert.equal(packageUpdateHelp('manual')?.command, undefined);
assert.equal(packageUpdateHelp('in-app'), undefined);
+9 -24
View File
@@ -64,38 +64,23 @@ export const toInstallKind = (value: unknown): InstallKind =>
export type PackageUpdateHelp = { command?: string; url: string; download: string };
/** The desktop updater's minisign public key (cinny-desktop tauri.conf.json). */
export const RELEASE_MINISIGN_KEY = 'RWRZZdyii05/NUcz337A5SAbiZK+NPVDWuiL2mM5Jk1p/LfRmNfiZ/6l';
/**
* [cinny-desktop #36] Download a Linux package and install it only after
* checking the release's minisign-signed SHA256SUMS.txt. Runs in a fresh temp
* directory so a stale SHA256SUMS.txt can't be picked up.
*/
const verifiedInstall = (file: string, install: string): string =>
[
`cd "$(mktemp -d)"`,
`curl -fLO ${RELEASE_DOWNLOAD}/${file} -fLO ${RELEASE_DOWNLOAD}/SHA256SUMS.txt -fLO ${RELEASE_DOWNLOAD}/SHA256SUMS.txt.minisig`,
`minisign -Vm SHA256SUMS.txt -P ${RELEASE_MINISIGN_KEY}`,
`sha256sum -c --ignore-missing SHA256SUMS.txt`,
`${install} ./${file}`,
].join(' && ');
export const packageUpdateHelp = (kind: InstallKind): PackageUpdateHelp | undefined => {
if (kind === 'pacman') {
// Install the local file: `pacman -U <url>` also fetches `<url>.sig` and
// fails without it (packages aren't signed for pacman), while a local file
// falls under LocalFileSigLevel. Integrity comes from SHA256SUMS.txt.
const url = `${RELEASE_DOWNLOAD}/LotusChat-x86_64.pkg.tar.zst`;
// Download first, then install the local file: `pacman -U <url>` also
// fetches `<url>.sig` and fails without it (we don't sign packages),
// while a local file falls under LocalFileSigLevel (signature optional).
return {
command: verifiedInstall('LotusChat-x86_64.pkg.tar.zst', 'sudo pacman -U'),
url: `${RELEASE_DOWNLOAD}/LotusChat-x86_64.pkg.tar.zst`,
command: `curl -LO ${url} && sudo pacman -U ./LotusChat-x86_64.pkg.tar.zst`,
url,
download: 'Download package',
};
}
if (kind === 'deb') {
const url = `${RELEASE_DOWNLOAD}/LotusChat-x86_64.deb`;
return {
command: verifiedInstall('LotusChat-x86_64.deb', 'sudo apt install'),
url: `${RELEASE_DOWNLOAD}/LotusChat-x86_64.deb`,
command: `curl -LO ${url} && sudo apt install ./LotusChat-x86_64.deb`,
url,
download: 'Download package',
};
}