excalidraw/src/data/index.ts

408 lines
11 KiB
TypeScript
Raw Normal View History

import { fileSave } from "browser-nativefs";
import { EVENT_IO, trackEvent } from "../analytics";
import { getDefaultAppState } from "../appState";
import {
copyCanvasToClipboardAsPng,
2020-09-04 14:58:32 +02:00
copyTextToSystemClipboard,
} from "../clipboard";
import {
ExcalidrawElement,
NonDeletedExcalidrawElement,
} from "../element/types";
import { t } from "../i18n";
import { exportToCanvas, exportToSvg } from "../scene/export";
import { ExportType } from "../scene/types";
import { AppState } from "../types";
import { canvasToBlob } from "./blob";
import { serializeAsJSON } from "./json";
import { restore } from "./restore";
2020-09-22 21:51:49 +02:00
import { ImportedDataState } from "./types";
export { loadFromBlob } from "./blob";
export { loadFromJSON, saveAsJSON } from "./json";
const BACKEND_GET = process.env.REACT_APP_BACKEND_V1_GET_URL;
const BACKEND_V2_POST = process.env.REACT_APP_BACKEND_V2_POST_URL;
const BACKEND_V2_GET = process.env.REACT_APP_BACKEND_V2_GET_URL;
export const SOCKET_SERVER = process.env.REACT_APP_SOCKET_SERVER_URL;
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
export type EncryptedData = {
data: ArrayBuffer;
iv: Uint8Array;
};
export type SocketUpdateDataSource = {
SCENE_INIT: {
type: "SCENE_INIT";
payload: {
elements: readonly ExcalidrawElement[];
};
};
SCENE_UPDATE: {
type: "SCENE_UPDATE";
payload: {
elements: readonly ExcalidrawElement[];
};
};
MOUSE_LOCATION: {
type: "MOUSE_LOCATION";
payload: {
2020-08-14 20:14:22 +02:00
socketId: string;
pointer: { x: number; y: number };
button: "down" | "up";
selectedElementIds: AppState["selectedElementIds"];
username: string;
};
};
};
export type SocketUpdateDataIncoming =
| SocketUpdateDataSource[keyof SocketUpdateDataSource]
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
| {
type: "INVALID_RESPONSE";
};
const byteToHex = (byte: number): string => `0${byte.toString(16)}`.slice(-2);
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
const generateRandomID = async () => {
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
const arr = new Uint8Array(10);
window.crypto.getRandomValues(arr);
return Array.from(arr, byteToHex).join("");
};
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
const generateEncryptionKey = async () => {
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
const key = await window.crypto.subtle.generateKey(
{
name: "AES-GCM",
length: 128,
},
true, // extractable
["encrypt", "decrypt"],
);
return (await window.crypto.subtle.exportKey("jwk", key)).k;
};
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
export const createIV = () => {
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
const arr = new Uint8Array(12);
return window.crypto.getRandomValues(arr);
};
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
export const getCollaborationLinkData = (link: string) => {
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
if (link.length === 0) {
return;
}
const hash = new URL(link).hash;
return hash.match(/^#room=([a-zA-Z0-9_-]+),([a-zA-Z0-9_-]+)$/);
};
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
export const generateCollaborationLink = async () => {
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
const id = await generateRandomID();
const key = await generateEncryptionKey();
return `${window.location.origin}${window.location.pathname}#room=${id},${key}`;
};
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
export const getImportedKey = (key: string, usage: KeyUsage) =>
window.crypto.subtle.importKey(
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
"jwk",
{
alg: "A128GCM",
ext: true,
k: key,
key_ops: ["encrypt", "decrypt"],
kty: "oct",
},
{
name: "AES-GCM",
length: 128,
},
false, // extractable
[usage],
);
export const encryptAESGEM = async (
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
data: Uint8Array,
key: string,
): Promise<EncryptedData> => {
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
const importedKey = await getImportedKey(key, "encrypt");
const iv = createIV();
return {
data: await window.crypto.subtle.encrypt(
{
name: "AES-GCM",
iv,
},
importedKey,
data,
),
iv,
};
};
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
export const decryptAESGEM = async (
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
data: ArrayBuffer,
key: string,
iv: Uint8Array,
): Promise<SocketUpdateDataIncoming> => {
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
try {
const importedKey = await getImportedKey(key, "decrypt");
const decrypted = await window.crypto.subtle.decrypt(
{
name: "AES-GCM",
iv,
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
},
importedKey,
data,
);
const decodedData = new TextDecoder("utf-8").decode(
new Uint8Array(decrypted) as any,
);
return JSON.parse(decodedData);
} catch (error) {
window.alert(t("alerts.decryptFailed"));
console.error(error);
}
return {
type: "INVALID_RESPONSE",
};
};
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
export const exportToBackend = async (
elements: readonly ExcalidrawElement[],
appState: AppState,
) => {
const json = serializeAsJSON(elements, appState);
const encoded = new TextEncoder().encode(json);
const key = await window.crypto.subtle.generateKey(
{
name: "AES-GCM",
length: 128,
},
true, // extractable
["encrypt", "decrypt"],
);
// The iv is set to 0. We are never going to reuse the same key so we don't
// need to have an iv. (I hope that's correct...)
const iv = new Uint8Array(12);
// We use symmetric encryption. AES-GCM is the recommended algorithm and
// includes checks that the ciphertext has not been modified by an attacker.
const encrypted = await window.crypto.subtle.encrypt(
{
name: "AES-GCM",
iv,
},
key,
encoded,
);
// We use jwk encoding to be able to extract just the base64 encoded key.
// We will hardcode the rest of the attributes when importing back the key.
const exportedKey = await window.crypto.subtle.exportKey("jwk", key);
try {
const response = await fetch(BACKEND_V2_POST, {
method: "POST",
body: encrypted,
});
const json = await response.json();
if (json.id) {
const url = new URL(window.location.href);
// We need to store the key (and less importantly the id) as hash instead
// of queryParam in order to never send it to the server
url.hash = `json=${json.id},${exportedKey.k!}`;
const urlString = url.toString();
window.prompt(`🔒${t("alerts.uploadedSecurly")}`, urlString);
trackEvent(EVENT_IO, "export", "backend");
} else if (json.error_class === "RequestTooLargeError") {
window.alert(t("alerts.couldNotCreateShareableLinkTooBig"));
} else {
window.alert(t("alerts.couldNotCreateShareableLink"));
}
} catch (error) {
console.error(error);
window.alert(t("alerts.couldNotCreateShareableLink"));
}
};
const importFromBackend = async (
id: string | null,
privateKey?: string | null,
2020-09-22 21:51:49 +02:00
): Promise<ImportedDataState> => {
try {
const response = await fetch(
privateKey ? `${BACKEND_V2_GET}${id}` : `${BACKEND_GET}${id}.json`,
);
if (!response.ok) {
window.alert(t("alerts.importBackendFailed"));
return {};
}
let data: ImportedDataState;
if (privateKey) {
const buffer = await response.arrayBuffer();
basic Socket.io implementation of collaborative editing (#879) * Enable collaborative syncing for elements * Don't fall back to local storage if using a room, as that is confusing * Use remote socket server * Send updates to new users when they join * ~ * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * prettier * Fix bug with remote pointers not changing on scroll * Enable collaborative syncing for elements * add mouse tracking * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * Add Live button and app state to support tracking collaborator counts * enable collaboration, rooms, and mouse tracking * fix syncing bugs and add a button to start syncing mid session * fix syncing bugs and add a button to start syncing mid session * Fix bug with remote pointers not changing on scroll * remove UI for collaboration * remove link * clean up lingering unused UI * set random IV passed per encrypted message, reduce room id length, refactored socket broadcasting API, rename room_id to room, removed throttling of pointer movement * fix package.json conflict
2020-03-09 08:48:25 -07:00
const key = await getImportedKey(privateKey, "decrypt");
const iv = new Uint8Array(12);
const decrypted = await window.crypto.subtle.decrypt(
{
name: "AES-GCM",
iv,
},
key,
buffer,
);
// We need to convert the decrypted array buffer to a string
const string = new window.TextDecoder("utf-8").decode(
new Uint8Array(decrypted) as any,
);
data = JSON.parse(string);
} else {
// Legacy format
data = await response.json();
}
trackEvent(EVENT_IO, "import");
return {
elements: data.elements || null,
appState: data.appState || null,
};
} catch (error) {
window.alert(t("alerts.importBackendFailed"));
console.error(error);
return {};
}
};
export const exportCanvas = async (
type: ExportType,
elements: readonly NonDeletedExcalidrawElement[],
appState: AppState,
canvas: HTMLCanvasElement,
{
exportBackground,
exportPadding = 10,
viewBackgroundColor,
name,
scale = 1,
shouldAddWatermark,
}: {
exportBackground: boolean;
exportPadding?: number;
viewBackgroundColor: string;
name: string;
scale?: number;
shouldAddWatermark: boolean;
},
) => {
if (elements.length === 0) {
return window.alert(t("alerts.cannotExportEmptyCanvas"));
}
if (type === "svg" || type === "clipboard-svg") {
const tempSvg = exportToSvg(elements, {
exportBackground,
viewBackgroundColor,
exportPadding,
2020-10-28 17:10:22 +00:00
scale,
shouldAddWatermark,
metadata:
appState.exportEmbedScene && type === "svg"
? await (
await import(/* webpackChunkName: "image" */ "./image")
).encodeSvgMetadata({
text: serializeAsJSON(elements, appState),
})
: undefined,
});
if (type === "svg") {
await fileSave(new Blob([tempSvg.outerHTML], { type: "image/svg+xml" }), {
fileName: `${name}.svg`,
extensions: [".svg"],
});
trackEvent(EVENT_IO, "export", "svg");
return;
} else if (type === "clipboard-svg") {
trackEvent(EVENT_IO, "export", "clipboard-svg");
2020-09-04 14:58:32 +02:00
copyTextToSystemClipboard(tempSvg.outerHTML);
return;
}
}
const tempCanvas = exportToCanvas(elements, appState, {
exportBackground,
viewBackgroundColor,
exportPadding,
scale,
shouldAddWatermark,
});
tempCanvas.style.display = "none";
document.body.appendChild(tempCanvas);
if (type === "png") {
const fileName = `${name}.png`;
let blob = await canvasToBlob(tempCanvas);
if (appState.exportEmbedScene) {
blob = await (
await import(/* webpackChunkName: "image" */ "./image")
).encodePngMetadata({
blob,
metadata: serializeAsJSON(elements, appState),
});
}
await fileSave(blob, {
fileName,
extensions: [".png"],
});
trackEvent(EVENT_IO, "export", "png");
} else if (type === "clipboard") {
try {
await copyCanvasToClipboardAsPng(tempCanvas);
trackEvent(EVENT_IO, "export", "clipboard-png");
} catch (error) {
if (error.name === "CANVAS_POSSIBLY_TOO_BIG") {
throw error;
}
throw new Error(t("alerts.couldNotCopyToClipboard"));
}
} else if (type === "backend") {
exportToBackend(elements, {
...appState,
viewBackgroundColor: exportBackground
? appState.viewBackgroundColor
: getDefaultAppState().viewBackgroundColor,
});
}
// clean up the DOM
if (tempCanvas !== canvas) {
tempCanvas.remove();
}
};
export const loadScene = async (
id: string | null,
privateKey: string | null,
// Supply initialData even if importing from backend to ensure we restore
// localStorage user settings which we do not persist on server.
// Non-optional so we don't forget to pass it even if `undefined`.
initialData: ImportedDataState | undefined | null,
) => {
let data;
if (id != null) {
// the private key is used to decrypt the content from the server, take
// extra care not to leak it
data = restore(
await importFromBackend(id, privateKey),
initialData?.appState,
);
} else {
data = restore(initialData || {}, null);
}
return {
elements: data.elements,
appState: data.appState,
commitToHistory: false,
};
};