diff --git a/api/src/middlewares/tokenAuth.js b/api/src/middlewares/tokenAuth.js new file mode 100644 index 000000000..82a801566 --- /dev/null +++ b/api/src/middlewares/tokenAuth.js @@ -0,0 +1,33 @@ + +import jwt from "jsonwebtoken"; +import { JWT_SECRET } from "../config"; +import { prisma } from "../db"; + + + + +export const authenticateToken = async (req, res, next) => { + const token = req.headers.authorization?.split(" ")[1]; // Bearer token extraction + if (!token) { + return res.status(401).json({ ok: false, error: "No token provided" }); + } + + try { + const decoded = jwt.verify(token, JWT_SECRET); + const user = await prisma.user.findUnique({ + where: { email: decoded.email }, + }); + + if (!user) { + return res.status(400).json({ ok: false, error: "User not found" }); + } + + // Attach user info to req object + req.user = user; + next(); // Proceed to the next middleware/route handler + } catch (error) { + return res.status(403).json({ ok: false, error: "Token is invalid or expired" }); + } +}; + +module.exports = { authenticateToken }; \ No newline at end of file diff --git a/expo/App.jsx b/expo/App.jsx index 1918367c9..1e224f6b5 100644 --- a/expo/App.jsx +++ b/expo/App.jsx @@ -60,46 +60,11 @@ const App = () => { ); useEffect(() => { - initMatomo().then(async () => { - if (!reconciliatedDrinksToDB) { - await reconciliateDrinksToDB(); - setReconciliatedDrinksToDB(true); - } - if (!reconciliatedGoalsToDB) { - await reconciliateGoalToDB(); - setReconciliatedGoalsToDB(true); - } - if (!_hasCleanConsoAndCatalog) { - await cleanConsosAndCatalog(); - setHasCleanConsoAndCatalog(true); - } - if (!_hasSentPreviousDrinksToDB) { - await sendPreviousDrinksToDB(); - setHasSentPreviousDrinksToDB(true); - } - if (!_hasMigrateFromDailyGoalToWeekly) { - await migrateFromDailyGoalToWeekly(); - sethasMigrateFromDailyGoalToWeekly(true); - } - if (!_hasMigrateMissingDrinkKey) { - migrateMissingDrinkKey(); - sethasMigrateMissingDrinkKey(true); - } - }); + initMatomo() // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - if ( - !reconciliatedDrinksToDB || - !reconciliatedGoalsToDB || - !_hasSentPreviousDrinksToDB || - !_hasCleanConsoAndCatalog || - !_hasMigrateFromDailyGoalToWeekly || - !_hasMigrateMissingDrinkKey - ) { - return null; - } return ( diff --git a/expo/src/Router.js b/expo/src/Router.js index 34ea27153..a73da7e98 100644 --- a/expo/src/Router.js +++ b/expo/src/Router.js @@ -1,4 +1,4 @@ -import React, { useEffect, useMemo, useRef } from "react"; +import React, { useEffect, useMemo, useRef, useState } from "react"; import { createBottomTabNavigator } from "@react-navigation/bottom-tabs"; import { NavigationContainer } from "@react-navigation/native"; import { Alert, Linking } from "react-native"; @@ -48,7 +48,6 @@ import StrategyModalNPS from "./components/StrategyModalNPS"; import { isInCravingKeyState } from "./recoil/craving"; import { dayjsInstance } from "./services/dates"; import SuccessStrategyModal from "./scenes/Craving/SuccessStrategyModal"; -import ExportedDataDone from "./scenes/Craving/ExportedDataDone"; import SigninScreen from "./scenes/Auth/Signin"; import SignupScreen from "./scenes/Auth/Signup"; import EmailConfirmationScreen from "./scenes/WelcomeScreen/EmailConfirmationScreen"; @@ -171,13 +170,50 @@ const TabsNavigator = ({ navigation }) => { const AppStack = createNativeStackNavigator(); const App = () => { + const [isTokenValid, setIsTokenValid] = useState(null); + const token = storage.getString("@Token"); + + useEffect(() => { + const checkTokenValidity = async () => { + if (!token) { + setIsTokenValid(false); + return; + } + + try { + const response = await API.get({ + path: "/user/signin_token", + headers: { Authorization: `Bearer ${token}` }, + }); + + if (response.ok) { + setIsTokenValid(true); + } else { + setIsTokenValid(false); + } + } catch (e) { + setIsTokenValid(false); + } + }; + + checkTokenValidity(); + }, [token]); + const initialRouteName = useMemo(() => { - const token = storage.getString("@Token"); + console.log("isTokenValid", isTokenValid); + if (isTokenValid === null) return null; // Still checking token, render a loading screen or nothing + + if (!isTokenValid) return "SIGNIN_SCREEN"; + const onBoardingDone = storage.getBoolean("@OnboardingDoneWithCGU"); - if (token) return "SIGNIN_SCREEN"; if (!onBoardingDone) return "WELCOME"; + return "TABS"; - }, []); + }, [isTokenValid]); + + if (initialRouteName === null) { + return null; // Render a loading screen or nothing until the token validity is checked + } return ( <> @@ -255,7 +291,6 @@ const Router = () => { }); prevCurrentRouteName.current = route.name; }; - const alreadyExported = storage.getBoolean("@ExportedData"); const handleInAppMessage = (inAppMessage) => { const [title, subTitle, actions = [], options = {}] = inAppMessage; @@ -289,7 +324,6 @@ const Router = () => { ref={navigationRef} onReady={() => { API.navigation = navigationRef.current; - if (alreadyExported) navigationRef.current.navigate("MODAL_EXPORT_DONE"); }} onStateChange={onNavigationStateChange} linking={deepLinkingConfig} @@ -325,15 +359,6 @@ const Router = () => { animation: "fade", }} /> - { animation: "fade", }} /> - { }; const signup = async () => { - // initMatomo(email, password); const matomoId = storage.getString("@UserIdv2"); const response = await API.post({ path: "/user/signup", @@ -165,10 +163,9 @@ const SignupScreen = ({ navigation }) => { navigation.navigate("EMAIL_CONFIRMATION")} + onPress={signup} className={`rounded-full px-6 py-3 ${isButtonDisabled ? "bg-[#EA6C96]" : "bg-[#de285e]"}`} - // disabled={isButtonDisabled} + disabled={isButtonDisabled} > Valider diff --git a/expo/src/services/logEventsWithMatomo.js b/expo/src/services/logEventsWithMatomo.js index 07fa1ce5f..8851a06fb 100644 --- a/expo/src/services/logEventsWithMatomo.js +++ b/expo/src/services/logEventsWithMatomo.js @@ -25,18 +25,6 @@ export const initMatomo = async () => { if (!userId) { userId = Matomo.makeid(); storage.set("@UserIdv2", userId); - const response = await API.post({ - path: "/user/signup", - body: { - matomoId: userId, - email: "yoanroszak@selego.co", - password: "password12@Abc", - calledFrom: "initMatomo", - }, - }); - if (response.ok) { - storage.set("@Token", response.token); - } } Sentry.setUser({ id: userId }); API.userId = userId; @@ -83,15 +71,6 @@ export const logEvent = async ({ category, action, name, value, dimension6 }) => const canSend = await checkNetwork(); if (!canSend) throw new Error("no network"); Matomo.logEvent({ category, action, name, value, dimension6 }); - const body = { - event: { category, action, name, value, dimension6 }, - userId: Matomo.userId, - dimensions: Matomo.dimensions, - }; - API.post({ - path: "/event", - body, - }); } catch (e) { console.log("logEvent error", e); console.log("logEvent error", { category, action, name, value, dimension6 }); diff --git a/expo/src/services/matomo.js b/expo/src/services/matomo.js index ab0a6f894..f210e65ee 100644 --- a/expo/src/services/matomo.js +++ b/expo/src/services/matomo.js @@ -75,7 +75,7 @@ class _Matomo { if (!this.initDone) throw new Error("matomo not initialized yet"); const url = `${this.baseUrl}?${this.computeParams(params, this.idsite)}`; if (__DEV__) { - // console.log(params, this.dimensions); + console.log(params, this.dimensions); return; } const res = await fetch(encodeURI(url)); diff --git a/expo/src/services/notifications.js b/expo/src/services/notifications.js index 8a0efecef..a6b142d9c 100644 --- a/expo/src/services/notifications.js +++ b/expo/src/services/notifications.js @@ -2,7 +2,6 @@ import * as Notifications from "expo-notifications"; import { Platform, AppState } from "react-native"; import { logEvent } from "./logEventsWithMatomo"; import { storage } from "./storage"; -import API from "./api"; class NotificationService { listeners = {}; @@ -41,14 +40,6 @@ class NotificationService { category: "PUSH_NOTIFICATION_TOKEN_REGISTER", action: "SUCCESS", }); - const matomoId = storage.getString("@UserIdv2"); - await API.put({ - path: "/user", - body: { - pushNotifToken: tokenPayload.data, - matomoId, - }, - }); }; onRegistrationError = (err) => {