diff --git a/package.json b/package.json index b87be4d4..93a825f9 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "react-helmet-async": "^1.3.0", "react-i18next": "^12.1.1", "react-router-dom": "^5.2.0", - "react-stickynode": "^4.1.0", + "react-sticky-el": "^2.1.0", "react-use": "^17.4.0", "slugify": "^1.6.6", "subsrt-ts": "^2.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b1bb42bb..7a140288 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -95,9 +95,9 @@ dependencies: react-router-dom: specifier: ^5.2.0 version: 5.3.4(react@17.0.2) - react-stickynode: - specifier: ^4.1.0 - version: 4.1.0(react-dom@17.0.2)(react@17.0.2) + react-sticky-el: + specifier: ^2.1.0 + version: 2.1.0(react-dom@17.0.2)(react@17.0.2) react-use: specifier: ^17.4.0 version: 17.4.0(react-dom@17.0.2)(react@17.0.2) @@ -3657,10 +3657,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /eventemitter3@3.1.2: - resolution: {integrity: sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==} - dev: false - /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -4595,6 +4591,7 @@ packages: /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true /loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} @@ -4994,10 +4991,6 @@ packages: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} dev: true - /performance-now@2.1.0: - resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} - dev: false - /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} dev: true @@ -5165,12 +5158,6 @@ packages: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true - /raf@3.4.1: - resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==} - dependencies: - performance-now: 2.1.0 - dev: false - /randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} dependencies: @@ -5286,19 +5273,14 @@ packages: tiny-warning: 1.0.3 dev: false - /react-stickynode@4.1.0(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-zylWgfad75jLfh/gYIayDcDWIDwO4weZrsZqDpjZ/axhF06zRjdCWFBgUr33Pvv2+htKWqPSFksWTyB6aMQ1ZQ==} + /react-sticky-el@2.1.0(react-dom@17.0.2)(react@17.0.2): + resolution: {integrity: sha512-oo+a2GedF4QMfCfm20e9gD+RuuQp/ngvwGMUXAXpST+h4WnmKhuv7x6MQ4X/e3AHiLYgE0zDyJo1Pzo8m51KpA==} peerDependencies: - react: ^0.14.2 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 - react-dom: ^0.14.2 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + react: '>=16.3.0' + react-dom: '>=16.3.0' dependencies: - classnames: 2.3.2 - core-js: 3.32.1 - prop-types: 15.8.1 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) - shallowequal: 1.1.0 - subscribe-ui-event: 2.0.7 dev: false /react-universal-interface@0.6.2(react@17.0.2)(tslib@2.6.2): @@ -5796,14 +5778,6 @@ packages: resolution: {integrity: sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ==} dev: false - /subscribe-ui-event@2.0.7: - resolution: {integrity: sha512-Acrtf9XXl6lpyHAWYeRD1xTPUQHDERfL4GHeNuYAtZMc4Z8Us2iDBP0Fn3xiRvkQ1FO+hx+qRLmPEwiZxp7FDQ==} - dependencies: - eventemitter3: 3.1.2 - lodash: 4.17.21 - raf: 3.4.1 - dev: false - /subsrt-ts@2.1.1: resolution: {integrity: sha512-E+GiLNG4L82yRDswd4ys34OUfJLNN6ZBdtefE7ftn/WJchjvyJ9dNXuXYviNglrqiCqNyayGGUZE3v9aL7zIYg==} hasBin: true diff --git a/src/backend/accounts/crypto.ts b/src/backend/accounts/crypto.ts index 00c53a08..f753ba27 100644 --- a/src/backend/accounts/crypto.ts +++ b/src/backend/accounts/crypto.ts @@ -70,7 +70,7 @@ export function base64ToBuffer(data: string) { return forge.util.binary.base64.decode(data); } -export function base64ToStringBugger(data: string) { +export function base64ToStringBuffer(data: string) { return forge.util.createBuffer(base64ToBuffer(data)); } @@ -97,7 +97,7 @@ export async function encryptData(data: string, secret: Uint8Array) { iv, tagLength: 128, }); - cipher.update(forge.util.createBuffer(data)); + cipher.update(forge.util.createBuffer(data, "utf8")); cipher.finish(); const encryptedData = cipher.output; @@ -118,11 +118,11 @@ export function decryptData(data: string, secret: Uint8Array) { forge.util.createBuffer(secret) ); decipher.start({ - iv: base64ToStringBugger(iv), - tag: base64ToStringBugger(tag), + iv: base64ToStringBuffer(iv), + tag: base64ToStringBuffer(tag), tagLength: 128, }); - decipher.update(base64ToStringBugger(encryptedData)); + decipher.update(base64ToStringBuffer(encryptedData)); const pass = decipher.finish(); if (!pass) throw new Error("Error decrypting data"); diff --git a/src/components/Avatar.tsx b/src/components/Avatar.tsx index 0ca96e9a..0b2933e2 100644 --- a/src/components/Avatar.tsx +++ b/src/components/Avatar.tsx @@ -1,5 +1,7 @@ import classNames from "classnames"; +import { useMemo } from "react"; +import { base64ToBuffer, decryptData } from "@/backend/accounts/crypto"; import { Icon, Icons } from "@/components/Icon"; import { UserIcon } from "@/components/UserIcon"; import { AccountProfile } from "@/pages/parts/auth/AccountCreatePart"; @@ -42,16 +44,40 @@ export function UserAvatar(props: { sizeClass?: string; iconClass?: string; bottom?: React.ReactNode; + withName?: boolean; }) { const auth = useAuthStore(); - if (!auth.account) return null; + + const bufferSeed = useMemo( + () => + auth.account && auth.account.seed + ? base64ToBuffer(auth.account.seed) + : null, + [auth] + ); + + if (!auth.account || auth.account === null) return null; + + const deviceName = bufferSeed + ? decryptData(auth.account.deviceName, bufferSeed) + : "..."; + return ( - + <> + + {props.withName && bufferSeed ? ( + + {deviceName.length >= 20 + ? `${deviceName.slice(0, 20 - 1)}…` + : deviceName} + + ) : null} + ); } diff --git a/src/components/LinksDropdown.tsx b/src/components/LinksDropdown.tsx index f8679c4f..7f3c5b02 100644 --- a/src/components/LinksDropdown.tsx +++ b/src/components/LinksDropdown.tsx @@ -107,12 +107,19 @@ export function LinksDropdown(props: { children: React.ReactNode }) { return (
evt.key === "Enter" && toggleOpen()} > {props.children} +
diff --git a/src/components/layout/Navigation.tsx b/src/components/layout/Navigation.tsx index ed666e53..8e56ffc1 100644 --- a/src/components/layout/Navigation.tsx +++ b/src/components/layout/Navigation.tsx @@ -101,7 +101,7 @@ export function Navigation(props: NavigationProps) {
- {loggedIn ? : } + {loggedIn ? : }
diff --git a/src/components/utils/Text.tsx b/src/components/utils/Text.tsx index 3151fb09..27d2ecb4 100644 --- a/src/components/utils/Text.tsx +++ b/src/components/utils/Text.tsx @@ -10,7 +10,7 @@ export function Heading1(props: TextProps) { return (

- Failed to fetch user data. Try resetting the backend URL. + {backendUrl !== userBackendUrl + ? "Failed to fetch user data. Try resetting the backend URL" + : "Failed to fetch user data."} ); return ; diff --git a/src/pages/Settings.tsx b/src/pages/Settings.tsx index 0f431ddb..edc497a2 100644 --- a/src/pages/Settings.tsx +++ b/src/pages/Settings.tsx @@ -42,7 +42,7 @@ function SettingsLayout(props: { children: React.ReactNode }) {
@@ -240,16 +240,24 @@ export function SettingsPage() {

You have unsaved changes

-
- -
diff --git a/src/pages/parts/home/HeroPart.tsx b/src/pages/parts/home/HeroPart.tsx index d45b3fe0..7df46a9c 100644 --- a/src/pages/parts/home/HeroPart.tsx +++ b/src/pages/parts/home/HeroPart.tsx @@ -1,5 +1,5 @@ import { useCallback, useState } from "react"; -import Sticky from "react-stickynode"; +import Sticky from "react-sticky-el"; import { ThinContainer } from "@/components/layout/ThinContainer"; import { SearchBarInput } from "@/components/SearchBar"; @@ -19,10 +19,9 @@ export function HeroPart({ setIsSticky, searchParams }: HeroPartProps) { const [, setShowBg] = useState(false); const bannerSize = useBannerSize(); const stickStateChanged = useCallback( - ({ status }: Sticky.Status) => { - const val = status === Sticky.STATUS_FIXED; - setShowBg(val); - setIsSticky(val); + (isFixed) => { + setShowBg(isFixed); + setIsSticky(isFixed); }, [setShowBg, setIsSticky] ); @@ -40,11 +39,13 @@ export function HeroPart({ setIsSticky, searchParams }: HeroPartProps) {
{title}
-
+
@@ -71,7 +71,7 @@ export function CaptionsPart(props: { return (
Captions -
+
-
+

Use custom proxy workers

@@ -103,7 +103,7 @@ function ProxyEdit({ proxyUrls, setProxyUrls }: ProxyEditProps) { function BackendEdit({ backendUrl, setBackendUrl }: BackendEditProps) { return ( -

+

Custom server

diff --git a/src/pages/parts/settings/SidebarPart.tsx b/src/pages/parts/settings/SidebarPart.tsx index 145122be..c85b3b6b 100644 --- a/src/pages/parts/settings/SidebarPart.tsx +++ b/src/pages/parts/settings/SidebarPart.tsx @@ -1,6 +1,5 @@ -import classNames from "classnames"; import { useCallback, useEffect, useState } from "react"; -import Sticky from "react-stickynode"; +import Sticky from "react-sticky-el"; import { useAsync } from "react-use"; import { getBackendMeta } from "@/backend/accounts/meta"; @@ -10,34 +9,25 @@ import { Divider } from "@/components/utils/Divider"; import { useBackendUrl } from "@/hooks/auth/useBackendUrl"; import { useIsMobile } from "@/hooks/useIsMobile"; import { conf } from "@/setup/config"; +import { useAuthStore } from "@/stores/auth"; -function BackendUrl(props: { url: string }) { - const url = props.url.replace(/https?:\/\//, ""); +const rem = 16; + +function SecureBadge(props: { url: string }) { const secure = props.url.startsWith("https://"); return ( -

-
- -
- {url} +
+ + Secure
); } export function SidebarPart() { const { isMobile } = useIsMobile(); + const { account } = useAuthStore(); // eslint-disable-next-line no-restricted-globals const hostname = location.hostname; - const rem = 16; const [activeLink, setActiveLink] = useState(""); const settingLinks = [ @@ -54,7 +44,6 @@ export function SidebarPart() { return getBackendMeta(backendUrl); }, [backendUrl]); - // TODO loading/error state for backend useEffect(() => { function recheck() { const windowHeight = @@ -97,11 +86,13 @@ export function SidebarPart() { }, []); return ( -
+
@@ -119,28 +110,56 @@ export function SidebarPart() {
-
- Version - {conf().APP_VERSION} +
+ {/* Hostname */} +
+

Hostname

+

{hostname}

+
+ + {/* Backend URL */} +
+

+ Backend URL + +

+

+ {backendUrl.replace(/https?:\/\//, "")} +

+
+ + {/* User ID */} +
+

User ID

+

{account?.userId ?? "Not logged in"}

+
+ + {/* App version */} +
+

App version

+

+ {conf().APP_VERSION} +

+
+ + {/* Backend version */} +
+

Backend version

+

+ {backendMeta.error ? ( + + ) : null} + {backendMeta.loading ? ( +

+ ) : ( + backendMeta?.value?.version || "Unknown" + )} +

+
-
- Domain - {hostname} -
- {backendMeta.value ? ( - <> -
- Backend Version - {backendMeta.value.version} -
-
- Backend URL - - - -
- - ) : null}
diff --git a/src/pages/parts/settings/ThemePart.tsx b/src/pages/parts/settings/ThemePart.tsx index 40237585..3bb73899 100644 --- a/src/pages/parts/settings/ThemePart.tsx +++ b/src/pages/parts/settings/ThemePart.tsx @@ -120,7 +120,7 @@ export function ThemePart(props: { return (
Appearance -
+
{/* default theme */}