FIX: Use Authorization header for PDF viewer instead of query parameter token
This commit is contained in:
@@ -10,6 +10,138 @@ import '../services/file_service.dart';
|
||||
import '../injection.dart';
|
||||
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'dart:io';
|
||||
|
||||
// Custom HTTP client for SfPdfViewer that injects Bearer token
|
||||
class AuthorizedHttpClient extends HttpClient {
|
||||
final String token;
|
||||
final HttpClient _inner = HttpClient();
|
||||
|
||||
AuthorizedHttpClient(this.token);
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> getUrl(Uri url) async {
|
||||
final request = await _inner.getUrl(url);
|
||||
request.headers.set('Authorization', 'Bearer $token');
|
||||
return request;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> openUrl(String method, Uri url) async {
|
||||
final request = await _inner.openUrl(method, url);
|
||||
request.headers.set('Authorization', 'Bearer $token');
|
||||
return request;
|
||||
}
|
||||
|
||||
@override
|
||||
set connectionTimeout(Duration? timeout) =>
|
||||
_inner.connectionTimeout = timeout;
|
||||
|
||||
@override
|
||||
Duration? get connectionTimeout => _inner.connectionTimeout;
|
||||
|
||||
@override
|
||||
set maxConnectionsPerHost(int? value) =>
|
||||
_inner.maxConnectionsPerHost = value;
|
||||
|
||||
@override
|
||||
int? get maxConnectionsPerHost => _inner.maxConnectionsPerHost;
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> delete(String host,
|
||||
[int port = 0, String requestPath = '/']) async {
|
||||
final request = await _inner.delete(host, port, requestPath);
|
||||
request.headers.set('Authorization', 'Bearer $token');
|
||||
return request;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> deleteUrl(Uri url) async {
|
||||
final request = await _inner.deleteUrl(url);
|
||||
request.headers.set('Authorization', 'Bearer $token');
|
||||
return request;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> get(String host,
|
||||
[int port = 0, String requestPath = '/']) async {
|
||||
final request = await _inner.get(host, port, requestPath);
|
||||
request.headers.set('Authorization', 'Bearer $token');
|
||||
return request;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> head(String host,
|
||||
[int port = 0, String requestPath = '/']) async {
|
||||
final request = await _inner.head(host, port, requestPath);
|
||||
request.headers.set('Authorization', 'Bearer $token');
|
||||
return request;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> headUrl(Uri url) async {
|
||||
final request = await _inner.headUrl(url);
|
||||
request.headers.set('Authorization', 'Bearer $token');
|
||||
return request;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> patch(String host,
|
||||
[int port = 0, String requestPath = '/']) async {
|
||||
final request = await _inner.patch(host, port, requestPath);
|
||||
request.headers.set('Authorization', 'Bearer $token');
|
||||
return request;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> patchUrl(Uri url) async {
|
||||
final request = await _inner.patchUrl(url);
|
||||
request.headers.set('Authorization', 'Bearer $token');
|
||||
return request;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> post(String host,
|
||||
[int port = 0, String requestPath = '/']) async {
|
||||
final request = await _inner.post(host, port, requestPath);
|
||||
request.headers.set('Authorization', 'Bearer $token');
|
||||
return request;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> postUrl(Uri url) async {
|
||||
final request = await _inner.postUrl(url);
|
||||
request.headers.set('Authorization', 'Bearer $token');
|
||||
return request;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> put(String host,
|
||||
[int port = 0, String requestPath = '/']) async {
|
||||
final request = await _inner.put(host, port, requestPath);
|
||||
request.headers.set('Authorization', 'Bearer $token');
|
||||
return request;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<HttpClientRequest> putUrl(Uri url) async {
|
||||
final request = await _inner.putUrl(url);
|
||||
request.headers.set('Authorization', 'Bearer $token');
|
||||
return request;
|
||||
}
|
||||
|
||||
@override
|
||||
set badCertificateCallback(
|
||||
bool Function(X509Certificate, String, int)? callback) =>
|
||||
_inner.badCertificateCallback = callback;
|
||||
|
||||
@override
|
||||
bool Function(X509Certificate, String, int)? get badCertificateCallback =>
|
||||
_inner.badCertificateCallback;
|
||||
|
||||
@override
|
||||
void close({bool force = false}) => _inner.close(force: force);
|
||||
}
|
||||
|
||||
// Modal version for overlay display
|
||||
class DocumentViewerModal extends StatefulWidget {
|
||||
@@ -180,13 +312,16 @@ class _DocumentViewerModalState extends State<DocumentViewerModal> {
|
||||
if (state.caps.isPdf) {
|
||||
// Log the URL being used for debugging
|
||||
print('Loading PDF from: ${state.viewUrl}');
|
||||
// Token is already included in the URL query parameter
|
||||
// Create custom HTTP client that injects the Bearer token
|
||||
final httpClient = AuthorizedHttpClient(state.token);
|
||||
// Token is passed via Authorization header, not in URL
|
||||
return SfPdfViewer.network(
|
||||
state.viewUrl.toString(),
|
||||
onDocumentLoadFailed: (details) {
|
||||
print('PDF load failed: ${details.error}');
|
||||
print('Description: ${details.description}');
|
||||
},
|
||||
httpClient: httpClient,
|
||||
);
|
||||
} else {
|
||||
return Container(
|
||||
|
||||
@@ -459,7 +459,8 @@ func viewerHandler(w http.ResponseWriter, r *http.Request, db *database.DB, jwtM
|
||||
errors.WriteError(w, errors.CodeInternal, "Server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
downloadPath := fmt.Sprintf("%s://%s/orgs/%s/files/download?path=%s&token=%s", scheme, host, orgID.String(), url.QueryEscape(file.Path), url.QueryEscape(viewerToken))
|
||||
// Download URL without token - will use Authorization header instead
|
||||
downloadPath := fmt.Sprintf("%s://%s/orgs/%s/files/download?path=%s", scheme, host, orgID.String(), url.QueryEscape(file.Path))
|
||||
|
||||
// Determine if it's a PDF based on file extension
|
||||
isPdf := strings.HasSuffix(strings.ToLower(file.Name), ".pdf")
|
||||
@@ -542,7 +543,8 @@ func userViewerHandler(w http.ResponseWriter, r *http.Request, db *database.DB,
|
||||
errors.WriteError(w, errors.CodeInternal, "Server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
downloadPath := fmt.Sprintf("%s://%s/user/files/download?path=%s&token=%s", scheme, host, url.QueryEscape(file.Path), url.QueryEscape(viewerToken))
|
||||
// Download URL without token - will use Authorization header instead
|
||||
downloadPath := fmt.Sprintf("%s://%s/user/files/download?path=%s", scheme, host, url.QueryEscape(file.Path))
|
||||
|
||||
// Determine if it's a PDF based on file extension
|
||||
isPdf := strings.HasSuffix(strings.ToLower(file.Name), ".pdf")
|
||||
|
||||
Reference in New Issue
Block a user