Floatplane channel plugin for Jellyfin 10.10.x: browse, HLS proxy, cookie session, CI release
Some checks failed
release / build-release (push) Has been cancelled
Some checks failed
release / build-release (push) Has been cancelled
- IChannel: creators -> sub-channels -> video posts (public listing API, search mapped) - IRequiresMediaInfoCallback -> signed proxy URLs; stream controller rewrites HLS so the AES-128 key is fetched server-side with the session cookie, segments stay on the CDN - delivery/info cached per token lifetime and throttled (~2/min) - config page: paste sails.sid + validate, extra creators, quality, search test - scripts/package.sh -> plugin folder + zip + md5 + manifest.json; Gitea release workflow - research docs, HAR analysis (HAR itself gitignored), install-pi5.sh Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
100
doc/research/reference-sources/floaty_middleware.dart
Normal file
100
doc/research/reference-sources/floaty_middleware.dart
Normal file
@@ -0,0 +1,100 @@
|
||||
import 'package:floaty/whitelabels.dart';
|
||||
import 'package:floaty/features/authentication/services/oauth2_service.dart';
|
||||
import 'package:floaty/features/api/repositories/fpapi.dart';
|
||||
import 'package:cookie_jar/cookie_jar.dart';
|
||||
|
||||
class Middleware {
|
||||
final OAuth2Service _oauth2Service = OAuth2Service.instance;
|
||||
|
||||
// Feature flag for cookie-based testing
|
||||
bool get useCookieAuth =>
|
||||
const bool.fromEnvironment('USE_COOKIE_AUTH', defaultValue: false);
|
||||
|
||||
/// Check if the user was previously authenticated (has stored tokens/cookies)
|
||||
/// This is different from isAuthenticated - it checks if credentials exist,
|
||||
/// not if they're currently valid
|
||||
Future<bool> wasPreviouslyAuthenticated(
|
||||
{String? whitelabelFriendlyName}) async {
|
||||
final whitelabelsToCheck = whitelabelFriendlyName != null
|
||||
? [whitelabels.getWhitelabel(whitelabelFriendlyName)]
|
||||
: whitelabels.getWhitelabels();
|
||||
|
||||
for (var whitelabel in whitelabelsToCheck) {
|
||||
final authMethod = await _oauth2Service.getAuthMethod(
|
||||
whitelabel: whitelabel.friendlyName);
|
||||
|
||||
final useCookie =
|
||||
(authMethod == 'cookie') || (authMethod == null && useCookieAuth);
|
||||
|
||||
if (!useCookie) {
|
||||
// Check if OAuth2 tokens exist (regardless of expiration)
|
||||
final hasTokens = await _oauth2Service.hasStoredTokens(
|
||||
whitelabel: whitelabel.friendlyName);
|
||||
if (hasTokens) return true;
|
||||
} else {
|
||||
// Check if cookies exist (regardless of expiration)
|
||||
final cookieJar = fpApiRequests.cookieJar;
|
||||
final uri = Uri.parse('https://${whitelabel.domain}/');
|
||||
final cookies = await cookieJar.loadForRequest(uri);
|
||||
|
||||
final authCookie = cookies.firstWhere(
|
||||
(c) => c.name == whitelabel.cookieName,
|
||||
orElse: () => Cookie('', ''),
|
||||
);
|
||||
|
||||
if (authCookie.name.isNotEmpty && authCookie.value.isNotEmpty) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<bool> isAuthenticated({String? whitelabelFriendlyName}) async {
|
||||
final whitelabelsToCheck = whitelabelFriendlyName != null
|
||||
? [whitelabels.getWhitelabel(whitelabelFriendlyName)]
|
||||
: whitelabels.getWhitelabels();
|
||||
|
||||
// Check each whitelabel
|
||||
for (var whitelabel in whitelabelsToCheck) {
|
||||
// Get the auth method for this whitelabel
|
||||
final authMethod = await _oauth2Service.getAuthMethod(
|
||||
whitelabel: whitelabel.friendlyName);
|
||||
|
||||
// If no auth method is set and we have the USE_COOKIE_AUTH flag, use cookies
|
||||
// Otherwise, default to OAuth2
|
||||
final useCookie =
|
||||
(authMethod == 'cookie') || (authMethod == null && useCookieAuth);
|
||||
|
||||
if (!useCookie) {
|
||||
// Check OAuth2 authentication
|
||||
final result = await _oauth2Service.isAuthenticated(
|
||||
whitelabel: whitelabel.friendlyName);
|
||||
if (result) return true;
|
||||
} else {
|
||||
// Check cookie authentication
|
||||
final cookieJar = fpApiRequests.cookieJar;
|
||||
final uri = Uri.parse('https://${whitelabel.domain}/');
|
||||
final cookies = await cookieJar.loadForRequest(uri);
|
||||
|
||||
final authCookie = cookies.firstWhere(
|
||||
(c) => c.name == whitelabel.cookieName,
|
||||
orElse: () => Cookie('', ''),
|
||||
);
|
||||
|
||||
if (authCookie.name.isNotEmpty && authCookie.value.isNotEmpty) {
|
||||
if (authCookie.expires != null &&
|
||||
authCookie.expires!.isAfter(DateTime.now())) {
|
||||
return true;
|
||||
} else {
|
||||
cookieJar.delete(uri);
|
||||
await whitelabels.removeLoggedInLabel(whitelabel.friendlyName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user