mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-04-21 08:41:57 +00:00
Update package dependencies and enhance Trakt authentication flow; add base64-js and react-native-url-polyfill to package.json, improve expo-auth-session integration with PKCE support in TraktSettingsScreen, and refactor token exchange method in traktService to include code verifier for enhanced security.
This commit is contained in:
parent
78583c8e80
commit
cc894ff4f4
4 changed files with 39 additions and 20 deletions
16
package-lock.json
generated
16
package-lock.json
generated
|
|
@ -24,6 +24,7 @@
|
||||||
"@types/lodash": "^4.17.16",
|
"@types/lodash": "^4.17.16",
|
||||||
"@types/react-native-video": "^5.0.20",
|
"@types/react-native-video": "^5.0.20",
|
||||||
"axios": "^1.8.4",
|
"axios": "^1.8.4",
|
||||||
|
"base64-js": "^1.5.1",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"eventemitter3": "^5.0.1",
|
"eventemitter3": "^5.0.1",
|
||||||
"expo": "~52.0.43",
|
"expo": "~52.0.43",
|
||||||
|
|
@ -40,7 +41,7 @@
|
||||||
"expo-screen-orientation": "~8.0.4",
|
"expo-screen-orientation": "~8.0.4",
|
||||||
"expo-status-bar": "~2.0.1",
|
"expo-status-bar": "~2.0.1",
|
||||||
"expo-system-ui": "^4.0.9",
|
"expo-system-ui": "^4.0.9",
|
||||||
"expo-web-browser": "^14.0.2",
|
"expo-web-browser": "~14.0.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
"react-native": "0.76.9",
|
"react-native": "0.76.9",
|
||||||
|
|
@ -56,6 +57,7 @@
|
||||||
"react-native-screens": "~4.4.0",
|
"react-native-screens": "~4.4.0",
|
||||||
"react-native-svg": "^15.11.2",
|
"react-native-svg": "^15.11.2",
|
||||||
"react-native-tab-view": "^4.0.10",
|
"react-native-tab-view": "^4.0.10",
|
||||||
|
"react-native-url-polyfill": "^2.0.0",
|
||||||
"react-native-video": "^6.12.0",
|
"react-native-video": "^6.12.0",
|
||||||
"react-native-web": "~0.19.13",
|
"react-native-web": "~0.19.13",
|
||||||
"subsrt": "^1.1.1"
|
"subsrt": "^1.1.1"
|
||||||
|
|
@ -11047,6 +11049,18 @@
|
||||||
"react-native-pager-view": ">= 6.0.0"
|
"react-native-pager-view": ">= 6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-native-url-polyfill": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-url-polyfill/-/react-native-url-polyfill-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-My330Do7/DvKnEvwQc0WdcBnFPploYKp9CYlefDXzIdEaA+PAhDYllkvGeEroEzvc4Kzzj2O4yVdz8v6fjRvhA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"whatwg-url-without-unicode": "8.0.0-3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react-native": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-native-vector-icons": {
|
"node_modules/react-native-vector-icons": {
|
||||||
"version": "10.2.0",
|
"version": "10.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-10.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-10.2.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,13 @@
|
||||||
"@types/lodash": "^4.17.16",
|
"@types/lodash": "^4.17.16",
|
||||||
"@types/react-native-video": "^5.0.20",
|
"@types/react-native-video": "^5.0.20",
|
||||||
"axios": "^1.8.4",
|
"axios": "^1.8.4",
|
||||||
|
"base64-js": "^1.5.1",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"eventemitter3": "^5.0.1",
|
"eventemitter3": "^5.0.1",
|
||||||
"expo": "~52.0.43",
|
"expo": "~52.0.43",
|
||||||
"expo-auth-session": "^6.0.3",
|
"expo-auth-session": "^6.0.3",
|
||||||
"expo-blur": "^14.0.3",
|
"expo-blur": "^14.0.3",
|
||||||
|
"expo-dev-client": "~5.0.20",
|
||||||
"expo-file-system": "^18.0.12",
|
"expo-file-system": "^18.0.12",
|
||||||
"expo-haptics": "~14.0.1",
|
"expo-haptics": "~14.0.1",
|
||||||
"expo-image": "~2.0.7",
|
"expo-image": "~2.0.7",
|
||||||
|
|
@ -40,7 +42,7 @@
|
||||||
"expo-screen-orientation": "~8.0.4",
|
"expo-screen-orientation": "~8.0.4",
|
||||||
"expo-status-bar": "~2.0.1",
|
"expo-status-bar": "~2.0.1",
|
||||||
"expo-system-ui": "^4.0.9",
|
"expo-system-ui": "^4.0.9",
|
||||||
"expo-web-browser": "^14.0.2",
|
"expo-web-browser": "~14.0.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
"react-native": "0.76.9",
|
"react-native": "0.76.9",
|
||||||
|
|
@ -56,10 +58,10 @@
|
||||||
"react-native-screens": "~4.4.0",
|
"react-native-screens": "~4.4.0",
|
||||||
"react-native-svg": "^15.11.2",
|
"react-native-svg": "^15.11.2",
|
||||||
"react-native-tab-view": "^4.0.10",
|
"react-native-tab-view": "^4.0.10",
|
||||||
|
"react-native-url-polyfill": "^2.0.0",
|
||||||
"react-native-video": "^6.12.0",
|
"react-native-video": "^6.12.0",
|
||||||
"react-native-web": "~0.19.13",
|
"react-native-web": "~0.19.13",
|
||||||
"subsrt": "^1.1.1",
|
"subsrt": "^1.1.1"
|
||||||
"expo-dev-client": "~5.0.20"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.25.2",
|
"@babel/core": "^7.25.2",
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import {
|
||||||
Platform,
|
Platform,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { useNavigation } from '@react-navigation/native';
|
import { useNavigation } from '@react-navigation/native';
|
||||||
import { makeRedirectUri, useAuthRequest, ResponseType } from 'expo-auth-session';
|
import { makeRedirectUri, useAuthRequest, ResponseType, Prompt, CodeChallengeMethod } from 'expo-auth-session';
|
||||||
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
|
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
|
||||||
import { traktService, TraktUser } from '../services/traktService';
|
import { traktService, TraktUser } from '../services/traktService';
|
||||||
import { colors } from '../styles/colors';
|
import { colors } from '../styles/colors';
|
||||||
|
|
@ -23,12 +23,11 @@ import TraktIcon from '../../assets/rating-icons/trakt.svg';
|
||||||
|
|
||||||
const ANDROID_STATUSBAR_HEIGHT = StatusBar.currentHeight || 0;
|
const ANDROID_STATUSBAR_HEIGHT = StatusBar.currentHeight || 0;
|
||||||
|
|
||||||
// Trakt configuration (replace with your actual Client ID if different)
|
// Trakt configuration
|
||||||
const TRAKT_CLIENT_ID = 'd7271f7dd57d8aeff63e99408610091a6b1ceac3b3a541d1031a48f429b7942c';
|
const TRAKT_CLIENT_ID = 'd7271f7dd57d8aeff63e99408610091a6b1ceac3b3a541d1031a48f429b7942c';
|
||||||
const discovery = {
|
const discovery = {
|
||||||
authorizationEndpoint: 'https://trakt.tv/oauth/authorize',
|
authorizationEndpoint: 'https://trakt.tv/oauth/authorize',
|
||||||
// Note: Trakt doesn't use a standard token endpoint for the auth code flow
|
tokenEndpoint: 'https://api.trakt.tv/oauth/token',
|
||||||
// We'll handle the code exchange manually in `traktService`
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// For use with deep linking
|
// For use with deep linking
|
||||||
|
|
@ -55,7 +54,7 @@ const TraktSettingsScreen: React.FC = () => {
|
||||||
const profile = await traktService.getUserProfile();
|
const profile = await traktService.getUserProfile();
|
||||||
setUserProfile(profile);
|
setUserProfile(profile);
|
||||||
} else {
|
} else {
|
||||||
setUserProfile(null); // Ensure profile is cleared if not authenticated
|
setUserProfile(null);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('[TraktSettingsScreen] Error checking auth status:', error);
|
logger.error('[TraktSettingsScreen] Error checking auth status:', error);
|
||||||
|
|
@ -68,13 +67,15 @@ const TraktSettingsScreen: React.FC = () => {
|
||||||
checkAuthStatus();
|
checkAuthStatus();
|
||||||
}, [checkAuthStatus]);
|
}, [checkAuthStatus]);
|
||||||
|
|
||||||
// Setup expo-auth-session hook
|
// Setup expo-auth-session hook with PKCE
|
||||||
const [request, response, promptAsync] = useAuthRequest(
|
const [request, response, promptAsync] = useAuthRequest(
|
||||||
{
|
{
|
||||||
clientId: TRAKT_CLIENT_ID,
|
clientId: TRAKT_CLIENT_ID,
|
||||||
scopes: [], // Trakt doesn't use scopes for standard auth code flow
|
scopes: [],
|
||||||
redirectUri: redirectUri,
|
redirectUri: redirectUri,
|
||||||
responseType: ResponseType.Code, // Ask for the authorization code
|
responseType: ResponseType.Code,
|
||||||
|
usePKCE: true,
|
||||||
|
codeChallengeMethod: CodeChallengeMethod.S256,
|
||||||
},
|
},
|
||||||
discovery
|
discovery
|
||||||
);
|
);
|
||||||
|
|
@ -84,15 +85,15 @@ const TraktSettingsScreen: React.FC = () => {
|
||||||
// Handle the response from the auth request
|
// Handle the response from the auth request
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (response) {
|
if (response) {
|
||||||
setIsExchangingCode(true); // Indicate we're processing the response
|
setIsExchangingCode(true);
|
||||||
if (response.type === 'success') {
|
if (response.type === 'success' && request?.codeVerifier) {
|
||||||
const { code } = response.params;
|
const { code } = response.params;
|
||||||
logger.log('[TraktSettingsScreen] Auth code received:', code);
|
logger.log('[TraktSettingsScreen] Auth code received:', code);
|
||||||
traktService.exchangeCodeForToken(code)
|
traktService.exchangeCodeForToken(code, request.codeVerifier)
|
||||||
.then(success => {
|
.then(success => {
|
||||||
if (success) {
|
if (success) {
|
||||||
logger.log('[TraktSettingsScreen] Token exchange successful');
|
logger.log('[TraktSettingsScreen] Token exchange successful');
|
||||||
checkAuthStatus(); // Re-check auth status and fetch profile
|
checkAuthStatus();
|
||||||
} else {
|
} else {
|
||||||
logger.error('[TraktSettingsScreen] Token exchange failed');
|
logger.error('[TraktSettingsScreen] Token exchange failed');
|
||||||
Alert.alert('Authentication Error', 'Failed to complete authentication with Trakt.');
|
Alert.alert('Authentication Error', 'Failed to complete authentication with Trakt.');
|
||||||
|
|
@ -110,12 +111,11 @@ const TraktSettingsScreen: React.FC = () => {
|
||||||
Alert.alert('Authentication Error', response.error?.message || 'An error occurred during authentication.');
|
Alert.alert('Authentication Error', response.error?.message || 'An error occurred during authentication.');
|
||||||
setIsExchangingCode(false);
|
setIsExchangingCode(false);
|
||||||
} else {
|
} else {
|
||||||
// Handle other response types like 'cancel', 'dismiss' if needed
|
|
||||||
logger.log('[TraktSettingsScreen] Auth response type:', response.type);
|
logger.log('[TraktSettingsScreen] Auth response type:', response.type);
|
||||||
setIsExchangingCode(false);
|
setIsExchangingCode(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [response, checkAuthStatus]);
|
}, [response, checkAuthStatus, request?.codeVerifier]);
|
||||||
|
|
||||||
const handleSignIn = () => {
|
const handleSignIn = () => {
|
||||||
promptAsync(); // Trigger the authentication flow
|
promptAsync(); // Trigger the authentication flow
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@ export class TraktService {
|
||||||
/**
|
/**
|
||||||
* Exchange the authorization code for an access token
|
* Exchange the authorization code for an access token
|
||||||
*/
|
*/
|
||||||
public async exchangeCodeForToken(code: string): Promise<boolean> {
|
public async exchangeCodeForToken(code: string, codeVerifier: string): Promise<boolean> {
|
||||||
await this.ensureInitialized();
|
await this.ensureInitialized();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -139,11 +139,14 @@ export class TraktService {
|
||||||
client_id: TRAKT_CLIENT_ID,
|
client_id: TRAKT_CLIENT_ID,
|
||||||
client_secret: TRAKT_CLIENT_SECRET,
|
client_secret: TRAKT_CLIENT_SECRET,
|
||||||
redirect_uri: TRAKT_REDIRECT_URI,
|
redirect_uri: TRAKT_REDIRECT_URI,
|
||||||
grant_type: 'authorization_code'
|
grant_type: 'authorization_code',
|
||||||
|
code_verifier: codeVerifier
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
const errorBody = await response.text();
|
||||||
|
logger.error('[TraktService] Token exchange error response:', errorBody);
|
||||||
throw new Error(`Failed to exchange code: ${response.status}`);
|
throw new Error(`Failed to exchange code: ${response.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue