From 3e9564d7b919b2535885da73399b22ddee33f102 Mon Sep 17 00:00:00 2001
From: Verticool
Date: Mon, 3 Feb 2025 11:04:15 +0600
Subject: [PATCH] auth flow fix, validation for auth in steps /uploadContnt
---
src/pages/root/steps/welcome-step/index.tsx | 23 ++--
src/pages/view-content/index.tsx | 89 ++++---------
src/shared/hooks/use-steps/index.ts | 33 +++--
src/shared/services/auth/index.ts | 139 ++++++++++++--------
src/shared/stores/root/index.ts | 2 +-
5 files changed, 147 insertions(+), 139 deletions(-)
diff --git a/src/pages/root/steps/welcome-step/index.tsx b/src/pages/root/steps/welcome-step/index.tsx
index 72172e3..80243d2 100644
--- a/src/pages/root/steps/welcome-step/index.tsx
+++ b/src/pages/root/steps/welcome-step/index.tsx
@@ -11,22 +11,27 @@ type WelcomeStepProps = {
export const WelcomeStep = ({ nextStep }: WelcomeStepProps) => {
const [tonConnectUI] = useTonConnectUI();
const [isLoaded, setLoaded] = useState(false);
-
+
console.log("💩💩💩 enter WelcomeStep");
const auth = useAuth();
console.log("💩💩💩 after useAuth");
-
- const handleNextClick = async () => {
- if (tonConnectUI.connected) {
- await auth.mutateAsync();
- nextStep();
- } else {
+
+const handleNextClick = async () => {
+ if (tonConnectUI.connected) {
+ await auth.mutateAsync();
+ nextStep();
+ } else {
+ try {
await tonConnectUI.openModal();
await auth.mutateAsync();
+ nextStep();
+ } catch (error) {
+ console.error('Failed to connect or authenticate:', error);
}
- };
+ }
+};
// useEffect(() => {
// const first = setTimeout(async () => {
@@ -104,4 +109,4 @@ export const WelcomeStep = ({ nextStep }: WelcomeStepProps) => {
/>
);
-};
+};
\ No newline at end of file
diff --git a/src/pages/view-content/index.tsx b/src/pages/view-content/index.tsx
index 5a07966..877d5a6 100644
--- a/src/pages/view-content/index.tsx
+++ b/src/pages/view-content/index.tsx
@@ -2,6 +2,7 @@ import ReactPlayer from "react-player/lazy";
import { useTonConnectUI } from "@tonconnect/ui-react";
import { useWebApp } from "@vkruglikov/react-telegram-web-app";
+import { Button } from "~/shared/ui/button";
import { usePurchaseContent, useViewContent } from "~/shared/services/content";
import { fromNanoTON } from "~/shared/utils";
import {useCallback, useEffect, useMemo} from "react";
@@ -71,54 +72,18 @@ export const ViewContentPage = () => {
}, []);
- useEffect(() => {
- const mainButton = WebApp.MainButton;
- const secondaryButton = WebApp.SecondaryButton;
-
- try {
- // Set main button color
- mainButton.color = '#e40615';
- mainButton.textColor = '#FFFFFF';
-
- // Set secondary button color
- secondaryButton.color = '#363636';
- secondaryButton.textColor = '#FFFFFF';
- if (!haveLicense) {
- mainButton.text = `Купить за ${fromNanoTON(content?.data?.encrypted?.license?.resale?.price)} ТОН`;
- mainButton.show();
- mainButton.onClick(handleBuyContent);
- } else {
- mainButton.hide();
- }
-
- secondaryButton.text = 'Загрузить свой контент';
- secondaryButton.show();
- secondaryButton.onClick(() => {
- WebApp.openTelegramLink('https://t.me/MY_UploaderRobot');
- });
-
- return () => {
- mainButton.hide();
- mainButton.offClick(handleBuyContent);
- secondaryButton.hide();
- secondaryButton.offClick();
- };
- } catch (error) {
- console.error('Error setting up Telegram WebApp buttons:', error);
- }
- }, [content, haveLicense, WebApp, handleBuyContent]);
-
+
return (
-
- {content?.data?.content_type.startsWith("audio") && content?.data?.display_options?.metadata?.image && (
-
-

-
- )}
+
+ {content?.data?.content_type.startsWith("audio") && content?.data?.display_options?.metadata?.image && (
+
+

+
+ )}
{content?.data?.content_type.startsWith("audio") ? (
@@ -146,21 +111,23 @@ export const ViewContentPage = () => {
- {/* {!haveLicense &&
- }
+
+ {!haveLicense &&
+ }
-
);
};
diff --git a/src/shared/hooks/use-steps/index.ts b/src/shared/hooks/use-steps/index.ts
index 7f632e4..311f069 100644
--- a/src/shared/hooks/use-steps/index.ts
+++ b/src/shared/hooks/use-steps/index.ts
@@ -1,4 +1,8 @@
-import { ReactNode, useMemo, useState } from "react";
+import { useTonConnectUI } from "@tonconnect/ui-react";
+import { ReactNode, useEffect, useMemo, useState } from "react";
+
+const CHECK_INTERVAL = 20000;
+
export const useSteps = (
sections: ({
@@ -9,15 +13,24 @@ export const useSteps = (
prevStep(): void;
}) => ReactNode[],
) => {
+
+ const [tonConnectUI] = useTonConnectUI();
+
const [step, setStep] = useState(0);
-
- const nextStep = () => {
- return setStep((s) => s + 1);
- };
-
- const prevStep = () => {
- return setStep((s) => s - 1);
- };
+
+ // If connection is lost, reset the step
+ useEffect(() => {
+ const interval = setInterval(() => {
+ if (!tonConnectUI.connected && step !== 0) {
+ setStep(0);
+ }
+ }, CHECK_INTERVAL);
+
+ return () => clearInterval(interval);
+ }, []);
+
+ const nextStep = () => setStep((s) => s + 1);
+ const prevStep = () => setStep((s) => s - 1);
const ActiveSection = useMemo(() => {
return sections({ nextStep, prevStep })[step];
@@ -28,4 +41,4 @@ export const useSteps = (
setStep,
step,
};
-};
+};
\ No newline at end of file
diff --git a/src/shared/services/auth/index.ts b/src/shared/services/auth/index.ts
index 0f6d859..fd0a308 100644
--- a/src/shared/services/auth/index.ts
+++ b/src/shared/services/auth/index.ts
@@ -13,80 +13,103 @@ export const useAuth = () => {
const [tonConnectUI] = useTonConnectUI();
const interval = useRef | undefined>();
+ const waitForWalletProof = async () => {
+ return new Promise((resolve, reject) => {
+ const timeout = setTimeout(() => reject(new Error("Timeout waiting for proof")), 30000);
+ const checkProof = setInterval(() => {
+ const currentWallet = tonConnectUI.wallet;
+ if (
+ currentWallet?.connectItems?.tonProof &&
+ !("error" in currentWallet.connectItems.tonProof)
+ ) {
+ clearInterval(checkProof);
+ clearTimeout(timeout);
+ resolve(currentWallet.connectItems.tonProof.proof);
+ }
+ }, 500);
+ });
+ };
+
+ const makeAuthRequest = async (params: {
+ twa_data: string;
+ ton_proof?: {
+ account: any;
+ ton_proof: any;
+ };
+ }) => {
+ const res = await request.post<{
+ connected_wallet: null | {
+ version: string;
+ address: string;
+ ton_balance: string;
+ };
+ auth_v1_token: string;
+ }>("/auth.twa", params);
+
+ if (res?.data?.auth_v1_token) {
+ localStorage.setItem(sessionStorageKey, res.data.auth_v1_token);
+ } else {
+ throw new Error("Failed to get auth token");
+ }
+ return res;
+ };
+
return useMutation(["auth"], async () => {
clearInterval(interval.current);
+ console.log("DEBUG: Starting auth flow");
- if (!wallet) {
+ // Case 1: Not connected - need to connect and get proof
+ if (!tonConnectUI.connected) {
+ console.log("DEBUG: No wallet connection, starting flow");
localStorage.removeItem(sessionStorageKey);
const refreshPayload = async () => {
tonConnectUI.setConnectRequestParameters({ state: "loading" });
-
- const value = await request
- .post<{
- auth_v1_token: string;
- }>("/auth.twa", {
- twa_data: WebApp.initData,
- })
- .catch((error: any) => {
- console.error("Error in authentication request: ", error);
- throw new Error("Failed to authenticate.");
- });
- if (!value) {
- tonConnectUI.setConnectRequestParameters(null);
- } else {
+ const value = await request.post<{ auth_v1_token: string }>("/auth.twa", {
+ twa_data: WebApp.initData,
+ });
+
+ if (value?.data?.auth_v1_token) {
tonConnectUI.setConnectRequestParameters({
state: "ready",
- value: {
- tonProof: value?.data?.auth_v1_token,
- },
+ value: { tonProof: value.data.auth_v1_token },
});
+ } else {
+ tonConnectUI.setConnectRequestParameters(null);
}
};
- void refreshPayload();
- setInterval(refreshPayload, payloadTTLMS);
+ await refreshPayload();
+ interval.current = setInterval(refreshPayload, payloadTTLMS);
- return;
+ const tonProof = await waitForWalletProof();
+ console.log("DEBUG: Got initial proof", tonProof);
+
+ return makeAuthRequest({
+ twa_data: WebApp.initData,
+ ton_proof: {
+ account: tonConnectUI.wallet!.account,
+ ton_proof: tonProof,
+ },
+ });
}
- if (
- wallet.connectItems?.tonProof &&
- !("error" in wallet.connectItems.tonProof)
- ) {
- const tonProof = wallet.connectItems.tonProof.proof;
-
- console.log("DEBUG TON-PROOF", tonProof);
-
- request
- .post<{
- connected_wallet: null | {
- version: string;
- address: string;
- ton_balance: string;
- };
- auth_v1_token: string;
- }>("/auth.twa", {
- twa_data: WebApp.initData,
- ton_proof: {
- account: wallet.account,
- ton_proof: tonProof,
- },
- })
- .then((res) => {
- if (res?.data?.auth_v1_token) {
- localStorage.setItem(sessionStorageKey, res?.data?.auth_v1_token);
- } else {
- alert("Please try another wallet");
- }
- })
- .catch((error: any) => {
- console.error("Error in authentication request: ", error);
- throw new Error("Failed to authenticate.");
- });
- } else {
- void tonConnectUI.disconnect();
- localStorage.removeItem(sessionStorageKey)
+ // Case 2: Connected with proof - use it
+ if (wallet?.connectItems?.tonProof && !("error" in wallet.connectItems.tonProof)) {
+ console.log("DEBUG: Using existing proof");
+ return makeAuthRequest({
+ twa_data: WebApp.initData,
+ ton_proof: {
+ account: wallet.account,
+ ton_proof: wallet.connectItems.tonProof.proof,
+ },
+ });
}
+
+ // Case 3: Connected without proof - already authenticated
+ console.log("DEBUG: Connected without proof, proceeding without it");
+ return makeAuthRequest({
+ twa_data: WebApp.initData,
+ });
});
};
\ No newline at end of file
diff --git a/src/shared/stores/root/index.ts b/src/shared/stores/root/index.ts
index 038e113..376d717 100644
--- a/src/shared/stores/root/index.ts
+++ b/src/shared/stores/root/index.ts
@@ -77,7 +77,7 @@ export const useRootStore = create((set) => ({
authors: [],
setAuthors: (authors) => set({ authors }),
- royalty: [{ address: "", value: 100 }],
+ royalty: [],
setRoyalty: (royalty) => set({ royalty }),
price: 0.15,