feat: add OAuth redirect handling and update Google OAuth integration
This commit is contained in:
@@ -22,7 +22,9 @@
|
|||||||
"Bash(source:*)",
|
"Bash(source:*)",
|
||||||
"Bash(npm install:*)",
|
"Bash(npm install:*)",
|
||||||
"Bash(npx tsc:*)",
|
"Bash(npx tsc:*)",
|
||||||
"Bash(npx expo:*)"
|
"Bash(npx expo:*)",
|
||||||
|
"Bash(find /var/home/felipecn/DEV/MeowSpool/mobile -name .env* -o -name *.env*)",
|
||||||
|
"Bash(grep -r \"useURL\\\\|useDeepLinking\\\\|Linking.parse\\\\|useLinkTo\" /var/home/felipecn/DEV/MeowSpool/mobile/app --include=*.tsx)"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { zodResolver } from '@hookform/resolvers/zod';
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { Ionicons } from '@expo/vector-icons';
|
import { Ionicons } from '@expo/vector-icons';
|
||||||
import * as Google from 'expo-auth-session/providers/google';
|
import * as Google from 'expo-auth-session/providers/google';
|
||||||
import * as WebBrowser from 'expo-web-browser';
|
|
||||||
import { Screen } from '@presentation/components/layout/Screen';
|
import { Screen } from '@presentation/components/layout/Screen';
|
||||||
import { Input } from '@presentation/components/ui/Input';
|
import { Input } from '@presentation/components/ui/Input';
|
||||||
import { Button } from '@presentation/components/ui/Button';
|
import { Button } from '@presentation/components/ui/Button';
|
||||||
@@ -16,9 +15,6 @@ import { loginUseCase, googleLoginUseCase } from '@infrastructure/container';
|
|||||||
import { useAuthStore } from '@store/authStore';
|
import { useAuthStore } from '@store/authStore';
|
||||||
import { CatIcon } from '@presentation/components/icons/CatIcon';
|
import { CatIcon } from '@presentation/components/icons/CatIcon';
|
||||||
|
|
||||||
// Necessário para fechar o browser após redirect OAuth no Android/iOS
|
|
||||||
WebBrowser.maybeCompleteAuthSession();
|
|
||||||
|
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
email: z.string().email('E-mail inválido'),
|
email: z.string().email('E-mail inválido'),
|
||||||
password: z.string().min(1, 'Senha obrigatória'),
|
password: z.string().min(1, 'Senha obrigatória'),
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import * as WebBrowser from 'expo-web-browser';
|
||||||
|
|
||||||
|
// Esta tela é o destino do redirect OAuth (meowspool://oauthredirect?code=...).
|
||||||
|
// maybeCompleteAuthSession() detecta os parâmetros da URL, sinaliza o
|
||||||
|
// expo-auth-session para fechar o browser e entregar o resultado ao hook
|
||||||
|
// useAuthRequest em login.tsx.
|
||||||
|
WebBrowser.maybeCompleteAuthSession();
|
||||||
|
|
||||||
|
export default function OAuthRedirect(): null {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
@@ -2,16 +2,15 @@
|
|||||||
* Plugin local: injeta o intent filter do Google OAuth no AndroidManifest.xml
|
* Plugin local: injeta o intent filter do Google OAuth no AndroidManifest.xml
|
||||||
* durante o `expo prebuild`.
|
* durante o `expo prebuild`.
|
||||||
*
|
*
|
||||||
* Sem esse intent filter, o Android não sabe que o MeowSpool deve interceptar
|
* expo-auth-session v5+ usa ${Application.applicationId}:/oauthredirect como
|
||||||
* o redirect do Google OAuth (scheme com.googleusercontent.apps.*), fazendo o
|
* redirect URI nativo (ex: com.meowspool.app:/oauthredirect).
|
||||||
* Chrome tratar a URL como pesquisa.
|
* Sem esse intent filter, o Android não intercepta o redirect e o Chrome
|
||||||
*
|
* trata a URL como pesquisa, redirecionando para o google.com.
|
||||||
* O scheme é o reverse do Android OAuth 2.0 client ID registrado no Google Cloud Console.
|
|
||||||
*/
|
*/
|
||||||
const { withAndroidManifest } = require('@expo/config-plugins');
|
const { withAndroidManifest } = require("@expo/config-plugins");
|
||||||
|
|
||||||
const GOOGLE_REVERSE_CLIENT_ID =
|
// Scheme gerado por expo-auth-session v7: applicationId do app
|
||||||
'com.googleusercontent.apps.724520558909-bg5a7e4u24jmis8lgg41ucs0kv0nfp1v';
|
const APP_SCHEME = "com.meowspool.app";
|
||||||
|
|
||||||
module.exports = function withGoogleOAuth(config) {
|
module.exports = function withGoogleOAuth(config) {
|
||||||
return withAndroidManifest(config, (config) => {
|
return withAndroidManifest(config, (config) => {
|
||||||
@@ -19,29 +18,29 @@ module.exports = function withGoogleOAuth(config) {
|
|||||||
const activities = manifest.manifest.application?.[0]?.activity ?? [];
|
const activities = manifest.manifest.application?.[0]?.activity ?? [];
|
||||||
|
|
||||||
const mainActivity = activities.find(
|
const mainActivity = activities.find(
|
||||||
(a) => a.$?.['android:name'] === '.MainActivity',
|
(a) => a.$?.["android:name"] === ".MainActivity",
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!mainActivity) return config;
|
if (!mainActivity) return config;
|
||||||
|
|
||||||
// Evita duplicar o intent filter em rebuilds consecutivos
|
// Evita duplicar o intent filter em rebuilds consecutivos
|
||||||
const alreadyAdded = (mainActivity['intent-filter'] ?? []).some((filter) =>
|
const alreadyAdded = (mainActivity["intent-filter"] ?? []).some((filter) =>
|
||||||
(filter.data ?? []).some(
|
(filter.data ?? []).some(
|
||||||
(d) => d.$?.['android:scheme'] === GOOGLE_REVERSE_CLIENT_ID,
|
(d) => d.$?.["android:scheme"] === APP_SCHEME,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (alreadyAdded) return config;
|
if (alreadyAdded) return config;
|
||||||
|
|
||||||
mainActivity['intent-filter'] = [
|
mainActivity["intent-filter"] = [
|
||||||
...(mainActivity['intent-filter'] ?? []),
|
...(mainActivity["intent-filter"] ?? []),
|
||||||
{
|
{
|
||||||
action: [{ $: { 'android:name': 'android.intent.action.VIEW' } }],
|
action: [{ $: { "android:name": "android.intent.action.VIEW" } }],
|
||||||
category: [
|
category: [
|
||||||
{ $: { 'android:name': 'android.intent.category.DEFAULT' } },
|
{ $: { "android:name": "android.intent.category.DEFAULT" } },
|
||||||
{ $: { 'android:name': 'android.intent.category.BROWSABLE' } },
|
{ $: { "android:name": "android.intent.category.BROWSABLE" } },
|
||||||
],
|
],
|
||||||
data: [{ $: { 'android:scheme': GOOGLE_REVERSE_CLIENT_ID } }],
|
data: [{ $: { "android:scheme": APP_SCHEME } }],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {
|
import {
|
||||||
SafeAreaView,
|
|
||||||
ScrollView,
|
ScrollView,
|
||||||
KeyboardAvoidingView,
|
KeyboardAvoidingView,
|
||||||
View,
|
View,
|
||||||
@@ -8,6 +7,7 @@ import {
|
|||||||
StyleSheet,
|
StyleSheet,
|
||||||
type ViewStyle,
|
type ViewStyle,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||||
import { colors, spacing } from '@shared/theme';
|
import { colors, spacing } from '@shared/theme';
|
||||||
|
|
||||||
interface ScreenProps {
|
interface ScreenProps {
|
||||||
|
|||||||
Reference in New Issue
Block a user