1
1
import 'package:flutter/material.dart' ;
2
2
import 'package:html/dom.dart' as dom;
3
3
4
+ import '../api/core.dart' ;
4
5
import '../api/model/model.dart' ;
5
6
import '../model/content.dart' ;
6
7
import '../model/store.dart' ;
@@ -184,7 +185,7 @@ class MessageImage extends StatelessWidget {
184
185
final src = node.srcUrl;
185
186
186
187
final store = PerAccountStoreWidget .of (context);
187
- final adjustedSrc = rewriteImageUrl (src, store.account);
188
+ final resolvedSrc = resolveUrl (src, store.account);
188
189
189
190
return Align (
190
191
alignment: Alignment .centerLeft,
@@ -200,8 +201,11 @@ class MessageImage extends StatelessWidget {
200
201
alignment: Alignment .center,
201
202
color: const Color .fromRGBO (0 , 0 , 0 , 0.03 ),
202
203
child: Image .network (
203
- adjustedSrc ,
204
+ resolvedSrc ,
204
205
filterQuality: FilterQuality .medium,
206
+ headers: isUrlOnRealm (resolvedSrc, store.account)
207
+ ? Map .fromEntries ([authHeader (store.account)])
208
+ : null ,
205
209
))));
206
210
}
207
211
}
@@ -442,7 +446,7 @@ class MessageImageEmoji extends StatelessWidget {
442
446
@override
443
447
Widget build (BuildContext context) {
444
448
final store = PerAccountStoreWidget .of (context);
445
- final adjustedSrc = rewriteImageUrl (node.src, store.account);
449
+ final resolvedSrc = resolveUrl (node.src, store.account);
446
450
447
451
const size = 20.0 ;
448
452
@@ -456,7 +460,10 @@ class MessageImageEmoji extends StatelessWidget {
456
460
// too low.
457
461
top: - 1.5 ,
458
462
child: Image .network (
459
- adjustedSrc.toString (),
463
+ resolvedSrc.toString (),
464
+ headers: isUrlOnRealm (resolvedSrc, store.account)
465
+ ? Map .fromEntries ([authHeader (store.account)])
466
+ : null ,
460
467
filterQuality: FilterQuality .medium,
461
468
width: size,
462
469
height: size,
@@ -469,32 +476,18 @@ class MessageImageEmoji extends StatelessWidget {
469
476
// Small helpers.
470
477
//
471
478
472
- /// Resolve URL if relative; add the user's API key if appropriate.
473
- ///
474
- /// The API key is added if the URL is on the realm, and is an endpoint
475
- /// known to require authentication (and to accept it in this form.)
476
- String rewriteImageUrl (String src, Account account) {
479
+ /// Resolve `src` to `account` 's realm, if relative
480
+ String resolveUrl (String url, Account account) {
477
481
final realmUrl = Uri .parse (account.realmUrl); // TODO clean this up
478
- final resolved = realmUrl.resolve (src); // TODO handle if fails to parse
479
-
480
- Uri adjustedSrc = resolved;
481
- if (resolved.origin == realmUrl.origin) {
482
- if (_kInlineApiRoutes.any ((regexp) => regexp.hasMatch (resolved.path))) {
483
- final delimiter = resolved.query.isNotEmpty ? '&' : '' ;
484
- adjustedSrc = resolved
485
- .resolve ('?${resolved .query }${delimiter }api_key=${account .apiKey }' );
486
- }
487
- }
488
-
489
- return adjustedSrc.toString ();
482
+ final resolved = realmUrl.resolve (url); // TODO handle if fails to parse
483
+ return resolved.toString ();
490
484
}
491
485
492
- /// List of routes which accept the API key appended as a GET parameter.
493
- final List <RegExp > _kInlineApiRoutes = [
494
- RegExp (r'^/user_uploads/' ),
495
- RegExp (r'^/thumbnail$' ),
496
- RegExp (r'^/avatar/' )
497
- ];
486
+ /// Whether the given absolute URL has the same origin as the account's realm.
487
+ // TODO: Take a `Uri` instead of String for `url`; remove "absolute" from doc
488
+ bool isUrlOnRealm (String url, Account account) {
489
+ return Uri .parse (url).origin == Uri .parse (account.realmUrl).origin;
490
+ }
498
491
499
492
InlineSpan _errorUnimplemented (UnimplementedNode node) {
500
493
// For now this shows error-styled HTML code even in release mode,
0 commit comments