Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be71931a81 |
@@ -89,8 +89,6 @@ import { zIndices } from '../styles/zIndex';
|
|||||||
|
|
||||||
const PIP_MIN_W = 200;
|
const PIP_MIN_W = 200;
|
||||||
const PIP_MIN_H = 112;
|
const PIP_MIN_H = 112;
|
||||||
/** Default PiP top: just below the 64px-ish room header. */
|
|
||||||
const PIP_DEFAULT_TOP = 72;
|
|
||||||
|
|
||||||
type Corner = 'se' | 'sw' | 'ne' | 'nw';
|
type Corner = 'se' | 'sw' | 'ne' | 'nw';
|
||||||
|
|
||||||
@@ -1048,11 +1046,8 @@ export function CallEmbedProvider({ children }: CallEmbedProviderProps) {
|
|||||||
el.style.left = `${Math.max(0, Math.min(savedPos.left, window.innerWidth - 280))}px`;
|
el.style.left = `${Math.max(0, Math.min(savedPos.left, window.innerWidth - 280))}px`;
|
||||||
el.style.top = `${Math.max(0, Math.min(savedPos.top, window.innerHeight - 158))}px`;
|
el.style.top = `${Math.max(0, Math.min(savedPos.top, window.innerHeight - 158))}px`;
|
||||||
} else {
|
} else {
|
||||||
// [Gitea #323] First use: top-right under the room header, over the
|
el.style.left = `${window.innerWidth - 280 - 16}px`;
|
||||||
// timeline. Bottom-right sat on the composer (Send / Emoji, and on
|
el.style.top = `${window.innerHeight - 158 - 72}px`;
|
||||||
// phones the whole message box), so typing landed on the call.
|
|
||||||
el.style.left = `${Math.max(0, window.innerWidth - 280 - 16)}px`;
|
|
||||||
el.style.top = `${PIP_DEFAULT_TOP}px`;
|
|
||||||
}
|
}
|
||||||
el.style.width = '280px';
|
el.style.width = '280px';
|
||||||
el.style.height = '158px';
|
el.style.height = '158px';
|
||||||
|
|||||||
@@ -47,8 +47,12 @@ import {
|
|||||||
recentForwardTargetsAtom,
|
recentForwardTargetsAtom,
|
||||||
addRecentForwardTarget,
|
addRecentForwardTarget,
|
||||||
} from '../../../state/recentForwardTargets';
|
} from '../../../state/recentForwardTargets';
|
||||||
import { buildForwardContent, buildPlaintextAttachmentContent } from './forwardContent';
|
import {
|
||||||
import { useLocalRoomNames } from '../../../hooks/useRoomMeta';
|
buildForwardContent,
|
||||||
|
buildPlaintextAttachmentContent,
|
||||||
|
forwardEncryptionWarning,
|
||||||
|
} from './forwardContent';
|
||||||
|
import { useLocalRoomNames, getLocalRoomName } from '../../../hooks/useRoomMeta';
|
||||||
|
|
||||||
type RoomRowProps = {
|
type RoomRowProps = {
|
||||||
room: Room;
|
room: Room;
|
||||||
@@ -275,6 +279,14 @@ export function ForwardMessageDialog({ mEvent, onClose }: Props) {
|
|||||||
// Selection persists across query changes: a room selected then filtered out
|
// Selection persists across query changes: a room selected then filtered out
|
||||||
// of the rendered slice stays selected.
|
// of the rendered slice stays selected.
|
||||||
const [selectedRoomIds, setSelectedRoomIds] = useState<Set<string>>(new Set());
|
const [selectedRoomIds, setSelectedRoomIds] = useState<Set<string>>(new Set());
|
||||||
|
const encryptionWarning = forwardEncryptionWarning(
|
||||||
|
!!mx.getRoom(mEvent.getRoomId() ?? '')?.hasEncryptionStateEvent(),
|
||||||
|
[...selectedRoomIds]
|
||||||
|
.map((id) => mx.getRoom(id))
|
||||||
|
.filter((r): r is Room => !!r && !r.hasEncryptionStateEvent())
|
||||||
|
// The name the user sees (their own "Rename for me" name, if set).
|
||||||
|
.map((r) => getLocalRoomName(mx, r.roomId) ?? r.name),
|
||||||
|
);
|
||||||
|
|
||||||
const toggleRoom = useCallback((roomId: string) => {
|
const toggleRoom = useCallback((roomId: string) => {
|
||||||
setSelectedRoomIds((prev) => {
|
setSelectedRoomIds((prev) => {
|
||||||
@@ -590,7 +602,13 @@ export function ForwardMessageDialog({ mEvent, onClose }: Props) {
|
|||||||
shrink="No"
|
shrink="No"
|
||||||
direction="Column"
|
direction="Column"
|
||||||
style={{ padding: `${config.space.S200} ${config.space.S400}` }}
|
style={{ padding: `${config.space.S200} ${config.space.S400}` }}
|
||||||
|
gap="200"
|
||||||
>
|
>
|
||||||
|
{encryptionWarning && (
|
||||||
|
<Text size="T200" role="note" style={{ color: color.Warning.Main }}>
|
||||||
|
{encryptionWarning}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
<Button
|
<Button
|
||||||
variant="Primary"
|
variant="Primary"
|
||||||
size="400"
|
size="400"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { test } from 'node:test';
|
import { test } from 'node:test';
|
||||||
import assert from 'node:assert/strict';
|
import assert from 'node:assert/strict';
|
||||||
import { MatrixClient, MatrixEvent } from 'matrix-js-sdk';
|
import { MatrixClient, MatrixEvent } from 'matrix-js-sdk';
|
||||||
import { buildForwardContent, getForwardedMeta } from './forwardContent';
|
import { buildForwardContent, forwardEncryptionWarning, getForwardedMeta } from './forwardContent';
|
||||||
|
|
||||||
// Pure content builder buildForwardContent: refuses undecryptable events, forwards
|
// Pure content builder buildForwardContent: refuses undecryptable events, forwards
|
||||||
// the latest edit (`m.new_content`), and strips reply fallbacks + `m.relates_to`.
|
// the latest edit (`m.new_content`), and strips reply fallbacks + `m.relates_to`.
|
||||||
@@ -171,3 +171,16 @@ test('getForwardedMeta rejects malformed metadata', () => {
|
|||||||
assert.equal(getForwardedMeta({ 'io.lotus.forwarded': { sender: 1 } }), undefined);
|
assert.equal(getForwardedMeta({ 'io.lotus.forwarded': { sender: 1 } }), undefined);
|
||||||
assert.equal(getForwardedMeta({}), undefined);
|
assert.equal(getForwardedMeta({}), undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('forwardEncryptionWarning: only from an encrypted room into unencrypted ones (#330)', () => {
|
||||||
|
assert.equal(forwardEncryptionWarning(false, ['general']), undefined);
|
||||||
|
assert.equal(forwardEncryptionWarning(true, []), undefined);
|
||||||
|
assert.match(
|
||||||
|
forwardEncryptionWarning(true, ['general']) ?? '',
|
||||||
|
/^general isn't encrypted\..*that room, along with who originally wrote it\.$/,
|
||||||
|
);
|
||||||
|
assert.match(
|
||||||
|
forwardEncryptionWarning(true, ['a', 'b']) ?? '',
|
||||||
|
/^2 of the rooms you picked aren't encrypted\..*those rooms/,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|||||||
@@ -122,3 +122,23 @@ export async function buildPlaintextAttachmentContent(
|
|||||||
|
|
||||||
return plainContent;
|
return plainContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [Gitea #330] The note shown when forwarding out of an encrypted room into
|
||||||
|
* rooms that aren't: the text (and a re-uploaded attachment) becomes readable
|
||||||
|
* by the server, and the original author is shown with it. Undefined when
|
||||||
|
* there's nothing to warn about.
|
||||||
|
*/
|
||||||
|
export function forwardEncryptionWarning(
|
||||||
|
sourceEncrypted: boolean,
|
||||||
|
unencryptedDestNames: string[],
|
||||||
|
): string | undefined {
|
||||||
|
if (!sourceEncrypted || unencryptedDestNames.length === 0) return undefined;
|
||||||
|
const where =
|
||||||
|
unencryptedDestNames.length === 1
|
||||||
|
? `${unencryptedDestNames[0]} isn't encrypted.`
|
||||||
|
: `${unencryptedDestNames.length} of the rooms you picked aren't encrypted.`;
|
||||||
|
return `${where} The forwarded message (and any attachment) will be readable by the server and everyone in ${
|
||||||
|
unencryptedDestNames.length === 1 ? 'that room' : 'those rooms'
|
||||||
|
}, along with who originally wrote it.`;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user