1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2024-12-29 15:11:58 +00:00

feat(mobile): Add support for Basic Authentication (#6840)

This commit is contained in:
rovo89 2024-02-04 21:35:13 +01:00 committed by GitHub
parent b4c211cad1
commit 5061c35c8d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 33 additions and 33 deletions

View file

@ -49,7 +49,7 @@ class AlbumThumbnailListTile extends StatelessWidget {
type: ThumbnailFormat.WEBP,
),
httpHeaders: {
"Authorization": "Bearer ${Store.get(StoreKey.accessToken)}",
"x-immich-user-token": Store.get(StoreKey.accessToken),
},
cacheKey: getAlbumThumbNailCacheKey(album, type: ThumbnailFormat.WEBP),
errorWidget: (context, url, error) =>

View file

@ -78,8 +78,7 @@ class GalleryViewerPage extends HookConsumerWidget {
final isPlayingMotionVideo = useState(false);
final isPlayingVideo = useState(false);
Offset? localPosition;
final authToken = 'Bearer ${Store.get(StoreKey.accessToken)}';
final header = {"Authorization": authToken};
final header = {"x-immich-user-token": Store.get(StoreKey.accessToken)};
final currentIndex = useState(initialIndex);
final currentAsset = loadAsset(currentIndex.value);
final isTrashEnabled =
@ -524,8 +523,7 @@ class GalleryViewerPage extends HookConsumerWidget {
imageUrl:
'${Store.get(StoreKey.serverEndpoint)}/asset/thumbnail/$assetId',
httpHeaders: {
"Authorization":
"Bearer ${Store.get(StoreKey.accessToken)}",
"x-immich-user-token": Store.get(StoreKey.accessToken),
},
errorWidget: (context, url, error) =>
const Icon(Icons.image_not_supported_outlined),

View file

@ -68,7 +68,7 @@ class VideoViewerPage extends HookConsumerWidget {
children: [
VideoPlayer(
url: videoUrl,
jwtToken: Store.get(StoreKey.accessToken),
accessToken: Store.get(StoreKey.accessToken),
isMotionVideo: isMotionVideo,
onVideoEnded: onVideoEnded,
onPaused: onPaused,
@ -99,7 +99,7 @@ final _fileFamily =
class VideoPlayer extends StatefulWidget {
final String? url;
final String? jwtToken;
final String? accessToken;
final File? file;
final bool isMotionVideo;
final VoidCallback onVideoEnded;
@ -114,7 +114,7 @@ class VideoPlayer extends StatefulWidget {
const VideoPlayer({
super.key,
this.url,
this.jwtToken,
this.accessToken,
this.file,
required this.onVideoEnded,
required this.isMotionVideo,
@ -160,7 +160,7 @@ class _VideoPlayerState extends State<VideoPlayer> {
videoPlayerController = widget.file == null
? VideoPlayerController.networkUrl(
Uri.parse(widget.url!),
httpHeaders: {"Authorization": "Bearer ${widget.jwtToken}"},
httpHeaders: {"x-immich-user-token": widget.accessToken ?? ""},
)
: VideoPlayerController.file(widget.file!);

View file

@ -302,8 +302,7 @@ class BackupService {
onProgress: ((bytes, totalBytes) =>
uploadProgressCb(bytes, totalBytes)),
);
req.headers["Authorization"] =
"Bearer ${Store.get(StoreKey.accessToken)}";
req.headers["x-immich-user-token"] = Store.get(StoreKey.accessToken);
req.headers["Transfer-Encoding"] = "chunked";
req.fields['deviceAssetId'] = entity.id;

View file

@ -89,8 +89,7 @@ class _AssetMarkerIcon extends StatelessWidget {
imageUrl,
cacheKey: cacheKey,
headers: {
"Authorization":
"Bearer ${Store.get(StoreKey.accessToken)}",
"x-immich-user-token": Store.get(StoreKey.accessToken),
},
errorListener: (_) =>
const Icon(Icons.image_not_supported_outlined),

View file

@ -27,7 +27,7 @@ class MemoryCard extends StatelessWidget {
super.key,
});
String get authToken => 'Bearer ${Store.get(StoreKey.accessToken)}';
String get accessToken => Store.get(StoreKey.accessToken);
@override
Widget build(BuildContext context) {
@ -55,7 +55,7 @@ class MemoryCard extends StatelessWidget {
cacheKey: getThumbnailCacheKey(
asset,
),
headers: {"Authorization": authToken},
headers: {"x-immich-user-token": accessToken},
),
fit: BoxFit.cover,
),

View file

@ -51,7 +51,7 @@ class CuratedPeopleRow extends StatelessWidget {
itemBuilder: (context, index) {
final person = content[index];
final headers = {
"Authorization": "Bearer ${Store.get(StoreKey.accessToken)}",
"x-immich-user-token": Store.get(StoreKey.accessToken),
};
return Padding(
padding: const EdgeInsets.only(right: 18.0),

View file

@ -46,8 +46,7 @@ class ThumbnailWithInfo extends StatelessWidget {
fit: BoxFit.cover,
imageUrl: imageUrl!,
httpHeaders: {
"Authorization":
"Bearer ${Store.get(StoreKey.accessToken)}",
"x-immich-user-token": Store.get(StoreKey.accessToken),
},
errorWidget: (context, url, error) =>
const Icon(Icons.image_not_supported_outlined),

View file

@ -123,8 +123,7 @@ class PersonResultPage extends HookConsumerWidget {
backgroundImage: NetworkImage(
getFaceThumbnailUrl(personId),
headers: {
"Authorization":
"Bearer ${Store.get(StoreKey.accessToken)}",
"x-immich-user-token": Store.get(StoreKey.accessToken),
},
),
),

View file

@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
@ -106,6 +108,10 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
final accessToken = Store.get(StoreKey.accessToken);
try {
final endpoint = Uri.parse(Store.get(StoreKey.serverEndpoint));
final headers = {"x-immich-user-token": accessToken};
if (endpoint.userInfo.isNotEmpty) {
headers["Authorization"] = "Basic ${base64.encode(utf8.encode(endpoint.userInfo))}";
}
debugPrint("Attempting to connect to websocket");
// Configure socket transports must be specified
@ -118,7 +124,7 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
.enableForceNew()
.enableForceNewConnection()
.enableAutoConnect()
.setExtraHeaders({"Authorization": "Bearer $accessToken"})
.setExtraHeaders(headers)
.build(),
);

View file

@ -31,12 +31,12 @@ class ApiService {
setEndpoint(endpoint);
}
}
String? _authToken;
String? _accessToken;
setEndpoint(String endpoint) {
_apiClient = ApiClient(basePath: endpoint);
if (_authToken != null) {
setAccessToken(_authToken!);
if (_accessToken != null) {
setAccessToken(_accessToken!);
}
userApi = UserApi(_apiClient);
authenticationApi = AuthenticationApi(_apiClient);
@ -134,8 +134,8 @@ class ApiService {
}
setAccessToken(String accessToken) {
_authToken = accessToken;
_apiClient.addDefaultHeader('Authorization', 'Bearer $accessToken');
_accessToken = accessToken;
_apiClient.addDefaultHeader('x-immich-user-token', accessToken);
}
ApiClient get apiClient => _apiClient;

View file

@ -95,11 +95,11 @@ class ImmichImage extends StatelessWidget {
},
);
}
final String? token = Store.get(StoreKey.accessToken);
final String? accessToken = Store.get(StoreKey.accessToken);
final String thumbnailRequestUrl = getThumbnailUrl(asset, type: type);
return CachedNetworkImage(
imageUrl: thumbnailRequestUrl,
httpHeaders: {"Authorization": "Bearer $token"},
httpHeaders: {"x-immich-user-token": accessToken ?? ""},
cacheKey: getThumbnailCacheKey(asset, type: type),
width: width,
height: height,
@ -177,7 +177,7 @@ class ImmichImage extends StatelessWidget {
getThumbnailUrlForRemoteId(assetId, type: type),
cacheKey: getThumbnailCacheKeyForRemoteId(assetId, type: type),
headers: {
"Authorization": 'Bearer ${Store.get(StoreKey.accessToken)}',
"x-immich-user-token": Store.get(StoreKey.accessToken),
},
);
@ -195,10 +195,10 @@ class ImmichImage extends StatelessWidget {
context,
);
} else {
final authToken = 'Bearer ${Store.get(StoreKey.accessToken)}';
final accessToken = Store.get(StoreKey.accessToken);
// Precache the remote image since we are not using local images
return precacheImage(
remoteThumbnailProvider(asset, type, {"Authorization": authToken}),
remoteThumbnailProvider(asset, type, {"x-immich-user-token": accessToken}),
context,
);
}

View file

@ -13,7 +13,7 @@ Widget userAvatar(BuildContext context, User u, {double? radius}) {
backgroundColor: context.primaryColor.withAlpha(50),
foregroundImage: CachedNetworkImageProvider(
url,
headers: {"Authorization": "Bearer ${Store.get(StoreKey.accessToken)}"},
headers: {"x-immich-user-token": Store.get(StoreKey.accessToken)},
cacheKey: "user-${u.id}-profile",
),
// silence errors if user has no profile image, use initials as fallback

View file

@ -51,7 +51,7 @@ class UserCircleAvatar extends ConsumerWidget {
placeholder: (_, __) => Image.memory(kTransparentImage),
imageUrl: profileImageUrl,
httpHeaders: {
"Authorization": "Bearer ${Store.get(StoreKey.accessToken)}",
"x-immich-user-token": Store.get(StoreKey.accessToken),
},
fadeInDuration: const Duration(milliseconds: 300),
errorWidget: (context, error, stackTrace) => textIcon,