Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions app/client/src/components/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import {
loadKeyPackageRecords,
loadMLSGroupStates,
loadMLSKeyPair,
reviveGroupState,
saveDecryptedMessages,
saveMLSGroupStates,
saveMLSKeyPair,
Expand Down Expand Up @@ -1535,7 +1536,10 @@ export function Chat() {
}
}
if (kpInputs.length > 0) {
const resAdd = await createCommitAndWelcomes(group, kpInputs);
const resAdd = await createCommitAndWelcomes(
reviveGroupState(group),
kpInputs,
);
const commitContent = encodePublicMessage(resAdd.commit);
const ok = await sendHandshake(
room.id,
Expand Down Expand Up @@ -1734,7 +1738,10 @@ export function Chat() {
}
}
if (kpInputs.length > 0) {
const resAdd = await createCommitAndWelcomes(group, kpInputs);
const resAdd = await createCommitAndWelcomes(
reviveGroupState(group),
kpInputs,
);
const commitContent = encodePublicMessage(resAdd.commit);
const toList = Array.from(
new Set([
Expand Down
82 changes: 43 additions & 39 deletions app/client/src/components/chat/ChatSettingsOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useMLS } from "../e2ee/useMLS.ts";
import {
getCacheItem,
loadMLSGroupStates,
reviveGroupState,
setCacheItem,
} from "../e2ee/storage.ts";
import type { StoredGroupState } from "../e2ee/mls_wrapper.ts";
Expand Down Expand Up @@ -408,7 +409,10 @@ export function ChatSettingsOverlay(props: ChatSettingsOverlayProps) {
const state = props.groupState;
if (!state) throw new Error("ルームの暗号状態が未初期化です");
// 追加用の Commit/Welcome を生成
const res = await createCommitAndWelcomes(state, [kpInput]);
const res = await createCommitAndWelcomes(
reviveGroupState(state),
[kpInput],
);
// Handshake として送信(commit と welcome)
const commitContent = encodePublicMessage(res.commit);
// 既知のメンバー(UIが持つ room.members)と自分を宛先に含める
Expand Down Expand Up @@ -581,62 +585,62 @@ export function ChatSettingsOverlay(props: ChatSettingsOverlayProps) {
</div>
</Show>
<div class="flex-1 flex flex-col p-6 gap-6">
<Show when={tab() === "general"}>
<section class="space-y-6">
<Show when={tab() === "general"}>
<section class="space-y-6">
<div>
<label class="block text-sm text-gray-400 mb-1">
ルーム名
ルーム名
</label>
<input
value={roomName()}
onInput={(e) => setRoomName(e.currentTarget.value)}
class="w-full bg-[#2b2b2b] border border-[#3a3a3a] rounded px-3 py-2 text-white focus:outline-none focus:border-blue-500"
placeholder="ルーム名"
value={roomName()}
onInput={(e) => setRoomName(e.currentTarget.value)}
class="w-full bg-[#2b2b2b] border border-[#3a3a3a] rounded px-3 py-2 text-white focus:outline-none focus:border-blue-500"
placeholder="ルーム名"
/>
</div>
<div>
<label class="block text-sm text-gray-400 mb-1">
アイコン
アイコン
</label>
<div class="flex items-center gap-4">
<div class="w-16 h-16 rounded-lg bg-[#2b2b2b] flex items-center justify-center overflow-hidden border border-[#3a3a3a]">
{roomIcon()
? (
<img
src={roomIcon()!}
alt="room icon"
class="w-full h-full object-cover"
<div class="w-16 h-16 rounded-lg bg-[#2b2b2b] flex items-center justify-center overflow-hidden border border-[#3a3a3a]">
{roomIcon()
? (
<img
src={roomIcon()!}
alt="room icon"
class="w-full h-full object-cover"
/>
)
: <span class="text-gray-500 text-xs">なし</span>}
</div>
<label class="px-3 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded cursor-pointer text-sm">
<input
type="file"
accept="image/*"
class="hidden"
style={{ display: "none" }}
onChange={(e) => {
const f = e.currentTarget.files?.[0];
if (f) handleIconChange(f);
}}
/>
)
: <span class="text-gray-500 text-xs">なし</span>}
</div>
<label class="px-3 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded cursor-pointer text-sm">
<input
type="file"
accept="image/*"
class="hidden"
style={{ display: "none" }}
onChange={(e) => {
const f = e.currentTarget.files?.[0];
if (f) handleIconChange(f);
}}
/>
{uploading() ? "アップロード中..." : "画像を選択"}
</label>
{uploading() ? "アップロード中..." : "画像を選択"}
</label>
</div>
</div>
<div>
<button
type="button"
disabled={saving()}
onClick={handleSaveGeneral}
class="px-4 py-2 bg-green-600 hover:bg-green-700 disabled:bg-gray-600 text-white rounded text-sm font-medium"
type="button"
disabled={saving()}
onClick={handleSaveGeneral}
class="px-4 py-2 bg-green-600 hover:bg-green-700 disabled:bg-gray-600 text-white rounded text-sm font-medium"
>
保存
保存
</button>
</div>
</section>
</Show>
</section>
</Show>
<Show when={tab() === "members"}>
<section class="space-y-6">
<Show when={props.bindingInfo}>
Expand Down
5 changes: 5 additions & 0 deletions app/client/src/components/e2ee/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ function deserializeGroupState(buf: ArrayBuffer): StoredGroupState {
return { ...obj, clientConfig: defaultClientConfig } as StoredGroupState;
}

// JSON 化などで失われた TypedArray を復元するヘルパー
export function reviveGroupState(state: StoredGroupState): StoredGroupState {
return deserializeGroupState(serializeGroupState(state));
}

export const loadMLSGroupStates = async (
accountId: string,
): Promise<Record<string, StoredGroupState>> => {
Expand Down