diff --git a/b0esche_cloud/lib/pages/public_file_viewer.dart b/b0esche_cloud/lib/pages/public_file_viewer.dart index 7599431..0957c45 100644 --- a/b0esche_cloud/lib/pages/public_file_viewer.dart +++ b/b0esche_cloud/lib/pages/public_file_viewer.dart @@ -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 { _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().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(); diff --git a/b0esche_cloud/pubspec.lock b/b0esche_cloud/pubspec.lock index 60f2505..76124ef 100644 --- a/b0esche_cloud/pubspec.lock +++ b/b0esche_cloud/pubspec.lock @@ -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" diff --git a/b0esche_cloud/pubspec.yaml b/b0esche_cloud/pubspec.yaml index 9bfb073..bb06634 100644 --- a/b0esche_cloud/pubspec.yaml +++ b/b0esche_cloud/pubspec.yaml @@ -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 diff --git a/go_cloud/api b/go_cloud/api index 9fc1859..f6f90b2 100755 Binary files a/go_cloud/api and b/go_cloud/api differ diff --git a/go_cloud/internal/http/routes.go b/go_cloud/internal/http/routes.go index 59f46ae..804082f 100644 --- a/go_cloud/internal/http/routes.go +++ b/go_cloud/internal/http/routes.go @@ -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", "*")