Skip to content
Merged
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
20 changes: 17 additions & 3 deletions apps/web/pages/_document.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,26 @@ import Document, { DocumentContext, Head, Html, Main, NextScript, DocumentProps
type Props = Record<string, unknown> & DocumentProps;

function toRunBeforeReactOnClient() {
window.sessionStorage.setItem("calEmbedMode", String(location.search.includes("embed=")));
const calEmbedMode = location.search.includes("embed=");
try {
// eslint-disable-next-line @calcom/eslint/avoid-web-storage
window.sessionStorage.setItem("calEmbedMode", String(calEmbedMode));
} catch (e) {}

window.isEmbed = () => {
return window.sessionStorage.getItem("calEmbedMode") === "true";
try {
// eslint-disable-next-line @calcom/eslint/avoid-web-storage
return window.sessionStorage.getItem("calEmbedMode") === "true";
} catch (e) {}
// If we can't use sessionStorage to retrieve embed mode, just use the variable. It would fail to detect embed if page in iframe reloads without embed query param in it.
return calEmbedMode;
};

window.resetEmbedStatus = () => {
window.sessionStorage.removeItem("calEmbedMode");
try {
// eslint-disable-next-line @calcom/eslint/avoid-web-storage
window.sessionStorage.removeItem("calEmbedMode");
} catch (e) {}
};

window.getEmbedTheme = () => {
Expand Down
3 changes: 3 additions & 0 deletions apps/web/pages/getting-started.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ import { UsernameAvailability } from "@components/ui/UsernameAvailability";

import { TRPCClientErrorLike } from "@trpc/client";

// Embed isn't applicable to onboarding, so ignore the rule
/* eslint-disable @calcom/eslint/avoid-web-storage */

type ScheduleFormValues = {
schedule: ScheduleType;
};
Expand Down
2 changes: 2 additions & 0 deletions apps/web/pages/settings/profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ function SettingsView(props: ComponentProps<typeof Settings> & { localeProp: str
const enteredTimeFormat = selectedTimeFormat.value;

// Write time format to localStorage if available
// Embed isn't applicable to profile pages. So ignore the rule
// eslint-disable-next-line @calcom/eslint/avoid-web-storage
window.localStorage.setItem("timeOption.is24hClock", selectedTimeFormat.value === 12 ? "false" : "true");

// TODO: Add validation
Expand Down
1 change: 1 addition & 0 deletions apps/web/playwright/onboarding.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ test.describe("Onboarding", () => {
*/
test.fixme();
await page.addInitScript(() => {
// eslint-disable-next-line @calcom/eslint/avoid-web-storage
window.localStorage.setItem("username", "alwaysavailable");
}, {});
// Try to go getting started with a available username
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/configs/recommended.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const recommended = {
parserOptions: { sourceType: "module" },
rules: {
"@calcom/eslint/deprecated-imports": "error",
"@calcom/eslint/avoid-web-storage": "error",
},
};

Expand Down
45 changes: 45 additions & 0 deletions packages/eslint-plugin/src/rules/avoid-web-storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { ESLintUtils } from "@typescript-eslint/utils";

const createRule = ESLintUtils.RuleCreator((name) => `https://developer.cal.com/eslint/rule/${name}`);
const rule = createRule({
create(context) {
return {
CallExpression(node) {
const webStorages = ["localStorage", "sessionStorage"];
const callee = node.callee;
if (
// Can't figure out how to fix this TS issue
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
callee.object?.object?.name === "window" &&
// Can't figure out how to fix this TS issue
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
webStorages.includes(node?.callee?.object?.property?.name)
) {
return context.report({
node: node,
loc: node.loc,
messageId: "possible-issue-with-embed",
});
}
},
};
},
name: "avoid-web-storage",
meta: {
fixable: "code",
docs: {
description: "Avoid deprecated imports",
recommended: "warn",
},
messages: {
"possible-issue-with-embed": `Be aware that accessing localStorage/sessionStorage throws error in Chrome Incognito mode when embed is in cross domain context. If you know what you are doing, \`import {localStorage, sessionStorage} from "@calcom/lib/webstorage"\` for safe usage. See https://github.com/calcom/cal.com/issues/2618`,
},
type: "suggestion",
schema: [],
},
defaultOptions: [],
});

export default rule;
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/rules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ import type { ESLint } from "eslint";
export default {
"my-first-rule": require("./my-first-rule").default,
"deprecated-imports": require("./deprecated-imports").default,
"avoid-web-storage": require("./avoid-web-storage").default,
} as ESLint.Plugin["rules"];
2 changes: 2 additions & 0 deletions packages/lib/webstorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
export const localStorage = {
getItem(key: string) {
try {
// eslint-disable-next-line @calcom/eslint/avoid-web-storage
return window.localStorage.getItem(key);
} catch (e) {
// In case storage is restricted. Possible reasons
Expand All @@ -11,6 +12,7 @@ export const localStorage = {
},
setItem(key: string, value: string) {
try {
// eslint-disable-next-line @calcom/eslint/avoid-web-storage
window.localStorage.setItem(key, value);
} catch (e) {
// In case storage is restricted. Possible reasons
Expand Down