From 880c4e91a3559137fd11894eacfffbd4e83172e2 Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Fri, 7 May 2021 16:01:29 +0000 Subject: [PATCH 1/7] Removed redirect clientside session logic from pages and moved to shell --- components/Shell.tsx | 11 +++++++---- pages/availability/event/[type].tsx | 8 +++----- pages/availability/index.tsx | 17 ++++++++--------- pages/index.tsx | 5 ----- pages/integrations/[integration].tsx | 4 ---- pages/integrations/index.tsx | 8 +++----- pages/settings/password.tsx | 7 +++---- pages/settings/profile.tsx | 7 +++---- 8 files changed, 27 insertions(+), 40 deletions(-) diff --git a/components/Shell.tsx b/components/Shell.tsx index 3810f5d5..c3cd0ca6 100644 --- a/components/Shell.tsx +++ b/components/Shell.tsx @@ -27,11 +27,14 @@ export default function Shell(props) { } const logoutHandler = () => { - signOut(); - router.push('/'); + signOut({ redirect: false }).then( () => router.push('/auth/logout') ); } - return ( + if ( ! loading && ! session ) { + router.replace('/auth/login'); + } + + return session && (
); -} +} \ No newline at end of file diff --git a/pages/availability/event/[type].tsx b/pages/availability/event/[type].tsx index 2c6e4bfd..8829c333 100644 --- a/pages/availability/event/[type].tsx +++ b/pages/availability/event/[type].tsx @@ -17,10 +17,6 @@ export default function EventType(props) { if (loading) { return

Loading...

; - } else { - if (!session) { - window.location.href = "/auth/login"; - } } async function updateEventTypeHandler(event) { @@ -164,7 +160,9 @@ export default function EventType(props) { export async function getServerSideProps(context) { const session = await getSession(context); - + if (!session) { + return { redirect: { permanent: false, destination: '/auth/login' } }; + } const user = await prisma.user.findFirst({ where: { email: session.user.email, diff --git a/pages/availability/index.tsx b/pages/availability/index.tsx index 83d0e715..df843edd 100644 --- a/pages/availability/index.tsx +++ b/pages/availability/index.tsx @@ -28,10 +28,6 @@ export default function Availability(props) { if (loading) { return

Loading...

; - } else { - if (!session) { - window.location.href = "/auth/login"; - } } function toggleAddModal() { @@ -141,11 +137,11 @@ export default function Availability(props) { - {props.types.map((eventType) => + {props.types.map((eventType) => {eventType.title} - {eventType.hidden && + {eventType.hidden && Hidden @@ -186,7 +182,7 @@ export default function Availability(props) {
- {showAddModal && + {showAddModal &&
@@ -284,7 +280,7 @@ export default function Availability(props) {
} - {showChangeTimesModal && + {showChangeTimesModal &&
@@ -353,6 +349,9 @@ export default function Availability(props) { export async function getServerSideProps(context) { const session = await getSession(context); + if (!session) { + return { redirect: { permanent: false, destination: '/auth/login' } }; + } const user = await prisma.user.findFirst({ where: { @@ -382,4 +381,4 @@ export async function getServerSideProps(context) { return { props: {user, types}, // will be passed to the page component as props } -} +} \ No newline at end of file diff --git a/pages/index.tsx b/pages/index.tsx index 572fad7b..7501b905 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -6,14 +6,9 @@ import { signIn, useSession, getSession } from 'next-auth/client'; export default function Home(props) { const [ session, loading ] = useSession(); - if (loading) { return

Loading...

; } - if (!session) { - window.location.href = "/auth/login"; - return; - } return(
diff --git a/pages/integrations/[integration].tsx b/pages/integrations/[integration].tsx index 6366122a..97849c39 100644 --- a/pages/integrations/[integration].tsx +++ b/pages/integrations/[integration].tsx @@ -13,10 +13,6 @@ export default function integration(props) { if (loading) { return

Loading...

; - } else { - if (!session) { - window.location.href = "/"; - } } function toggleShowAPIKey() { diff --git a/pages/integrations/index.tsx b/pages/integrations/index.tsx index 76e16a34..8cc36a67 100644 --- a/pages/integrations/index.tsx +++ b/pages/integrations/index.tsx @@ -13,10 +13,6 @@ export default function Home({ integrations }) { if (loading) { return

Loading...

; - } else { - if (!session) { - window.location.href = "/"; - } } function toggleAddModal() { @@ -181,7 +177,9 @@ const validJson = (jsonString: string) => { export async function getServerSideProps(context) { const session = await getSession(context); - + if (!session) { + return { redirect: { permanent: false, destination: '/auth/login' } }; + } const user = await prisma.user.findFirst({ where: { email: session.user.email, diff --git a/pages/settings/password.tsx b/pages/settings/password.tsx index cb937516..edeb06b0 100644 --- a/pages/settings/password.tsx +++ b/pages/settings/password.tsx @@ -15,10 +15,6 @@ export default function Settings(props) { if (loading) { return

Loading...

; - } else { - if (!session) { - window.location.href = "/auth/login"; - } } const closeSuccessModal = () => { setSuccessModalOpen(false); } @@ -88,6 +84,9 @@ export default function Settings(props) { export async function getServerSideProps(context) { const session = await getSession(context); + if (!session) { + return { redirect: { permanent: false, destination: '/auth/login' } }; + } const user = await prisma.user.findFirst({ where: { diff --git a/pages/settings/profile.tsx b/pages/settings/profile.tsx index 7974ad40..74aa19b5 100644 --- a/pages/settings/profile.tsx +++ b/pages/settings/profile.tsx @@ -22,10 +22,6 @@ export default function Settings(props) { if (loading) { return

Loading...

; - } else { - if (!session) { - window.location.href = "/auth/login"; - } } const closeSuccessModal = () => { setSuccessModalOpen(false); } @@ -159,6 +155,9 @@ export default function Settings(props) { export async function getServerSideProps(context) { const session = await getSession(context); + if (!session) { + return { redirect: { permanent: false, destination: '/auth/login' } }; + } const user = await prisma.user.findFirst({ where: { From 3739d7752d174dd5b05ad50c0d9e181629c16b5a Mon Sep 17 00:00:00 2001 From: vklimontovich Date: Fri, 7 May 2021 20:05:33 +0300 Subject: [PATCH 2/7] Telemetry enhancements (mainly, data masking improvements) - data masking is moved to a separate function; - hostnames and urls are masked now - collect pageview for pages not wrapped in Shell --- components/Shell.tsx | 4 ++-- lib/telemetry.ts | 37 ++++++++++++++++++++++++++++++++++++- pages/[user]/book.tsx | 6 +++--- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/components/Shell.tsx b/components/Shell.tsx index 3810f5d5..b3b861f7 100644 --- a/components/Shell.tsx +++ b/components/Shell.tsx @@ -3,7 +3,7 @@ import {useContext, useEffect, useState} from "react"; import { useRouter } from "next/router"; import { signOut, useSession } from 'next-auth/client'; import { MenuIcon, XIcon } from '@heroicons/react/outline'; -import {TelemetryContext, useTelemetry} from "../lib/telemetry"; +import {collectPageParameters, telemetryEventTypes, useTelemetry} from "../lib/telemetry"; export default function Shell(props) { const router = useRouter(); @@ -14,7 +14,7 @@ export default function Shell(props) { useEffect(() => { telemetry.withJitsu((jitsu) => { - return jitsu.track('page_view', {page_url: router.pathname, page_title: "", source_ip: ""}) + return jitsu.track(telemetryEventTypes.pageView, collectPageParameters(router.pathname)) }); }, [telemetry]) diff --git a/lib/telemetry.ts b/lib/telemetry.ts index 5cc38163..c1047c9e 100644 --- a/lib/telemetry.ts +++ b/lib/telemetry.ts @@ -1,6 +1,16 @@ import React, {useContext} from 'react' import {jitsuClient, JitsuClient} from "@jitsu/sdk-js"; +/** + * Enumeration of all event types that are being sent + * to telemetry collection. + */ +export const telemetryEventTypes = { + pageView: 'page_view', + dateSelected: 'date_selected', + timeSelected: 'time_selected', + bookingConfirmed: 'booking_confirmed' +} /** * Telemetry client @@ -21,6 +31,31 @@ function useTelemetry(): TelemetryClient { return useContext(TelemetryContext); } +function isLocalhost(host: string) { + return "localhost" === host || "127.0.0.1" === host; +} + +/** + * Collects page parameters and makes sure no sensitive data made it to telemetry + * @param route current next.js route + */ +export function collectPageParameters(route?: string): any { + let host = document.location.hostname; + let maskedHost = isLocalhost(host) ? "localhost" : "masked"; + //starts with '' + let docPath = route ?? ""; + return { + page_url: route, + page_title: "", + source_ip: "", + url: document.location.protocol + "//" + host + (docPath ?? ""), + doc_host: maskedHost, + doc_search: "", + doc_path: docPath, + referer: "", + } +} + function createTelemetryClient(): TelemetryClient { if (process.env.NEXT_PUBLIC_TELEMETRY_KEY) { return { @@ -36,7 +71,7 @@ function createTelemetryClient(): TelemetryClient { window['jitsu'] = jitsuClient({ log_level: 'ERROR', tracking_host: "https://t.calendso.com", - key: "js.2pvs2bbpqq1zxna97wcml.oi2jzirnbj1ev4tc57c5r", + key: process.env.NEXT_PUBLIC_TELEMETRY_KEY, cookie_name: "__clnds", capture_3rd_party_cookies: false, }); diff --git a/pages/[user]/book.tsx b/pages/[user]/book.tsx index 9e270b84..ce56b0f6 100644 --- a/pages/[user]/book.tsx +++ b/pages/[user]/book.tsx @@ -3,7 +3,7 @@ import Link from 'next/link'; import { useRouter } from 'next/router'; import { ClockIcon, CalendarIcon } from '@heroicons/react/solid'; import prisma from '../../lib/prisma'; -import {useTelemetry} from "../../lib/telemetry"; +import {collectPageParameters, telemetryEventTypes, useTelemetry} from "../../lib/telemetry"; import {useEffect} from "react"; const dayjs = require('dayjs'); @@ -12,12 +12,12 @@ export default function Book(props) { const { date, user } = router.query; const telemetry = useTelemetry(); useEffect(() => { - telemetry.withJitsu(jitsu => jitsu.track('time_selected', { page_title: "", source_ip: "" })); + telemetry.withJitsu(jitsu => jitsu.track(telemetryEventTypes.timeSelected, collectPageParameters())); }) const bookingHandler = event => { event.preventDefault(); - telemetry.withJitsu(jitsu => jitsu.track('booking_confirmed', { page_title: "", source_ip: "" })); + telemetry.withJitsu(jitsu => jitsu.track(telemetryEventTypes.bookingConfirmed, collectPageParameters())); const res = fetch( '/api/book/' + user, { From db05c587a3a68a8361580051ee04a127161072b1 Mon Sep 17 00:00:00 2001 From: vklimontovich Date: Fri, 7 May 2021 20:07:36 +0300 Subject: [PATCH 3/7] collect pageview for pages not wrapped in Shell --- pages/[user]/[type].tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pages/[user]/[type].tsx b/pages/[user]/[type].tsx index 3e5a201d..4c3401db 100644 --- a/pages/[user]/[type].tsx +++ b/pages/[user]/[type].tsx @@ -17,7 +17,7 @@ dayjs.extend(utc); dayjs.extend(timezone); import getSlots from '../../lib/slots'; -import {useTelemetry} from "../../lib/telemetry"; +import {collectPageParameters, telemetryEventTypes, useTelemetry} from "../../lib/telemetry"; function classNames(...classes) { return classes.filter(Boolean).join(' ') @@ -34,7 +34,7 @@ export default function Type(props) { const telemetry = useTelemetry(); const [selectedTimeZone, setSelectedTimeZone] = useState(''); - + function toggleTimeOptions() { setIsTimeOptionsOpen(!isTimeOptionsOpen); } @@ -44,6 +44,10 @@ export default function Type(props) { setSelectedTimeZone(dayjs.tz.guess()) }, []) + useEffect(() => { + telemetry.withJitsu((jitsu) => jitsu.track(telemetryEventTypes.pageView, collectPageParameters())) + }) + // Get router variables const router = useRouter(); @@ -91,7 +95,7 @@ export default function Type(props) { // Combine placeholder days with actual days const calendar = [...emptyDays, ...days.map((day) => - {isTimeOptionsOpen && + {isTimeOptionsOpen &&
Time Options
From 44e5158941f40938be52fd04d1587781e3dc306d Mon Sep 17 00:00:00 2001 From: Peer Richelsen Date: Fri, 7 May 2021 19:18:41 +0100 Subject: [PATCH 4/7] added powered by calendso --- pages/[user]/[type].tsx | 262 ++++++++++++++++++---------- public/calendso-logo-white-word.svg | 41 +++++ 2 files changed, 214 insertions(+), 89 deletions(-) create mode 100644 public/calendso-logo-white-word.svg diff --git a/pages/[user]/[type].tsx b/pages/[user]/[type].tsx index 3e5a201d..817b8bd5 100644 --- a/pages/[user]/[type].tsx +++ b/pages/[user]/[type].tsx @@ -153,98 +153,182 @@ export default function Type(props) { ); return ( -
- - {props.eventType.title} | {props.user.name || props.user.username} | Calendso - - +
+ + + {props.eventType.title} | {props.user.name || props.user.username} | + Calendso + + + -
-
-
-
- {props.user.avatar && Avatar} -

{props.user.name}

-

{props.eventType.title}

-

- - {props.eventType.length} minutes -

- - {isTimeOptionsOpen && -
-
-
Time Options
-
- - - am/pm - - - Use setting - - - 24h - - -
-
- setSelectedTimeZone(value)} className="mb-2 shadow-sm focus:ring-blue-500 focus:border-blue-500 mt-1 block w-full sm:text-sm border-gray-300 rounded-md" /> -
- } -

{props.eventType.description}

-
-
-
- {dayjs().month(selectedMonth).format("MMMM YYYY")} -
- - -
-
-
-
Sun
-
Mon
-
Tue
-
Wed
-
Thu
-
Fri
-
Sat
- {calendar} -
-
- {selectedDate &&
-
- {dayjs(selectedDate).format("dddd DD MMMM YYYY")} -
- {!loading ? availableTimes :
} -
} +
+
+
+
+ {props.user.avatar && ( + Avatar + )} +

{props.user.name}

+

+ {props.eventType.title} +

+

+ + {props.eventType.length} minutes +

+ + {isTimeOptionsOpen && ( +
+
+
Time Options
+
+ + + am/pm + + + Use setting + + + 24h + + +
+ setSelectedTimeZone(value)} + className="mb-2 shadow-sm focus:ring-blue-500 focus:border-blue-500 mt-1 block w-full sm:text-sm border-gray-300 rounded-md" + /> +
+ )} +

+ {props.eventType.description} +

+
+
+
+ + {dayjs().month(selectedMonth).format("MMMM YYYY")} + +
+ + +
-
-
+
+
+ Sun +
+
+ Mon +
+
+ Tue +
+
+ Wed +
+
+ Thu +
+
+ Fri +
+
+ Sat +
+ {calendar} +
+
+ {selectedDate && ( +
+
+ + {dayjs(selectedDate).format("dddd DD MMMM YYYY")} + +
+ {!loading ? availableTimes :
} +
+ )} +
+
+ {/* note(peer): + you can remove calendso branding here, but we'd also appreciate it, if you don't <3 + */} + + +
); } diff --git a/public/calendso-logo-white-word.svg b/public/calendso-logo-white-word.svg new file mode 100644 index 00000000..c1cf6431 --- /dev/null +++ b/public/calendso-logo-white-word.svg @@ -0,0 +1,41 @@ + + + + + + From 52d9f94711c836a9f39c1732be27f1340b7deba6 Mon Sep 17 00:00:00 2001 From: Peer Richelsen Date: Fri, 7 May 2021 19:21:42 +0100 Subject: [PATCH 5/7] inverted color --- pages/[user]/[type].tsx | 2 +- public/calendso-logo-white-word.svg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/[user]/[type].tsx b/pages/[user]/[type].tsx index 817b8bd5..bc33e1a2 100644 --- a/pages/[user]/[type].tsx +++ b/pages/[user]/[type].tsx @@ -316,7 +316,7 @@ export default function Type(props) { */}
- + powered by{" "} - + powered by{" "} Calendso Logo diff --git a/public/calendso-logo-word.svg b/public/calendso-logo-word.svg new file mode 100644 index 00000000..4a01ade1 --- /dev/null +++ b/public/calendso-logo-word.svg @@ -0,0 +1,41 @@ + + + + + + From edec0226c401d089ee06fb29d54668462b01cc0b Mon Sep 17 00:00:00 2001 From: Bailey Pumfleet Date: Fri, 7 May 2021 20:34:03 +0100 Subject: [PATCH 7/7] Update branding link to calendso.com --- pages/[user]/[type].tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/[user]/[type].tsx b/pages/[user]/[type].tsx index 53d8f849..0a2399e9 100644 --- a/pages/[user]/[type].tsx +++ b/pages/[user]/[type].tsx @@ -315,7 +315,7 @@ export default function Type(props) { you can remove calendso branding here, but we'd also appreciate it, if you don't <3 */}
- +