Implement authentication check and redirect for internal file access in PublicFileViewer
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:web/web.dart' as web;
|
||||
import 'dart:ui_web' as ui_web;
|
||||
@@ -9,6 +10,8 @@ import '../services/api_client.dart';
|
||||
import '../injection.dart';
|
||||
import '../theme/modern_glass_button.dart';
|
||||
import '../widgets/file_viewer_dispatch.dart';
|
||||
import '../blocs/auth/auth_bloc.dart';
|
||||
import '../blocs/auth/auth_state.dart';
|
||||
|
||||
class PublicFileViewer extends StatefulWidget {
|
||||
final String token;
|
||||
@@ -49,6 +52,18 @@ class _PublicFileViewerState extends State<PublicFileViewer> {
|
||||
_isLoading = false;
|
||||
});
|
||||
|
||||
// If user is authenticated and has internal access, redirect to internal viewer
|
||||
if (_fileData?['fileId'] != null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
final authState = context.read<AuthBloc>().state;
|
||||
if (authState is AuthAuthenticated) {
|
||||
final orgId = _fileData!['orgId'] ?? '';
|
||||
final fileId = _fileData!['fileId'];
|
||||
context.go('/viewer/$orgId/$fileId');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize video player if it's a video file
|
||||
if (_isVideoFile()) {
|
||||
await _initializeVideoPlayer();
|
||||
|
||||
@@ -359,7 +359,7 @@ packages:
|
||||
source: hosted
|
||||
version: "2.2.3"
|
||||
flutter_web_plugins:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
|
||||
@@ -65,6 +65,8 @@ dependencies:
|
||||
syncfusion_flutter_core: ^31.2.18
|
||||
just_audio_web: ^0.4.16
|
||||
just_audio: ^0.10.5
|
||||
flutter_web_plugins:
|
||||
sdk: flutter
|
||||
|
||||
dev_dependencies:
|
||||
flutter_lints: ^5.0.0
|
||||
|
||||
BIN
go_cloud/api
BIN
go_cloud/api
Binary file not shown.
@@ -2956,43 +2956,72 @@ func publicFileShareHandler(w http.ResponseWriter, r *http.Request, db *database
|
||||
downloadPath := fmt.Sprintf("%s://%s/public/share/%s/download?token=%s", scheme, host, token, url.QueryEscape(viewerToken))
|
||||
viewPath := fmt.Sprintf("%s://%s/public/share/%s/view?token=%s", scheme, host, token, url.QueryEscape(viewerToken))
|
||||
|
||||
// Check if user is authenticated and has access to the file
|
||||
var internalOrgId *string
|
||||
var internalFileId *string
|
||||
authHeader := r.Header.Get("Authorization")
|
||||
if authHeader != "" && strings.HasPrefix(authHeader, "Bearer ") {
|
||||
jwtToken := strings.TrimPrefix(authHeader, "Bearer ")
|
||||
claims, err := jwtManager.Validate(jwtToken)
|
||||
if err == nil {
|
||||
userID, err := uuid.Parse(claims.Subject)
|
||||
if err == nil {
|
||||
// Check if user has access
|
||||
if file.UserID != nil && *file.UserID == userID {
|
||||
// Personal file, user is owner
|
||||
fileIDStr := file.ID.String()
|
||||
internalOrgId = nil // personal
|
||||
internalFileId = &fileIDStr
|
||||
} else if link.OrgID != nil {
|
||||
// Org file, check if user is in org
|
||||
for _, orgIDStr := range claims.OrgIDs {
|
||||
orgID, err := uuid.Parse(orgIDStr)
|
||||
if err == nil && orgID == *link.OrgID {
|
||||
fileIDStr := file.ID.String()
|
||||
internalOrgId = &orgIDStr
|
||||
internalFileId = &fileIDStr
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determine file type
|
||||
isPdf := strings.HasSuffix(strings.ToLower(file.Name), ".pdf")
|
||||
mimeType := getMimeType(file.Name)
|
||||
|
||||
viewerSession := struct {
|
||||
FileName string `json:"fileName"`
|
||||
FileSize int64 `json:"fileSize"`
|
||||
DownloadUrl string `json:"downloadUrl"`
|
||||
ViewUrl string `json:"viewUrl,omitempty"`
|
||||
Token string `json:"token"`
|
||||
Capabilities struct {
|
||||
CanEdit bool `json:"canEdit"`
|
||||
CanAnnotate bool `json:"canAnnotate"`
|
||||
IsPdf bool `json:"isPdf"`
|
||||
MimeType string `json:"mimeType"`
|
||||
} `json:"capabilities"`
|
||||
}{
|
||||
FileName: file.Name,
|
||||
FileSize: file.Size,
|
||||
DownloadUrl: downloadPath,
|
||||
Token: viewerToken,
|
||||
viewerSession := map[string]interface{}{
|
||||
"fileName": file.Name,
|
||||
"fileSize": file.Size,
|
||||
"downloadUrl": downloadPath,
|
||||
"token": viewerToken,
|
||||
"capabilities": map[string]interface{}{
|
||||
"canEdit": false,
|
||||
"canAnnotate": false,
|
||||
"isPdf": isPdf,
|
||||
"mimeType": mimeType,
|
||||
},
|
||||
}
|
||||
|
||||
// Set view URL for PDFs, videos, audio, and documents (for inline viewing)
|
||||
if isPdf || strings.HasPrefix(mimeType, "video/") || strings.HasPrefix(mimeType, "audio/") {
|
||||
viewerSession.ViewUrl = viewPath
|
||||
viewerSession["viewUrl"] = viewPath
|
||||
} else if strings.Contains(mimeType, "document") || strings.Contains(mimeType, "word") || strings.Contains(mimeType, "spreadsheet") || strings.Contains(mimeType, "presentation") {
|
||||
// Use Collabora for document viewing
|
||||
wopiSrc := fmt.Sprintf("%s://%s/public/wopi/share/%s", scheme, host, token)
|
||||
collaboraUrl := fmt.Sprintf("https://of.b0esche.cloud/lool/dist/mobile/cool.html?WOPISrc=%s", url.QueryEscape(wopiSrc))
|
||||
viewerSession.ViewUrl = collaboraUrl
|
||||
viewerSession["viewUrl"] = collaboraUrl
|
||||
}
|
||||
|
||||
viewerSession.Capabilities.CanEdit = false
|
||||
viewerSession.Capabilities.CanAnnotate = false
|
||||
viewerSession.Capabilities.IsPdf = isPdf
|
||||
viewerSession.Capabilities.MimeType = mimeType
|
||||
// Add internal access info if user has access
|
||||
if internalFileId != nil {
|
||||
viewerSession["fileId"] = *internalFileId
|
||||
if internalOrgId != nil {
|
||||
viewerSession["orgId"] = *internalOrgId
|
||||
}
|
||||
}
|
||||
|
||||
// Add CORS headers for public access
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
|
||||
Reference in New Issue
Block a user