Skip to content

Commit dd72ae2

Browse files
committed
lightbox: Use tryGetFileDownloadUrl to download images.
Using the helper `tryGetFileDownloadUrl`, we try to generate and use temporary authless URLs to download files from the lighbox. This fixes an issue where redirects to S3 caused RNFetchBlob to fail downloading the file. If we fail to download the file, which happens if we failed to generate the temporary URL because the server does not support it, we open it in the browser instead, from where the user can easily save it. Also makes changes in other places required due to this change. Fixes: #2115
1 parent db89a5c commit dd72ae2

File tree

4 files changed

+36
-19
lines changed

4 files changed

+36
-19
lines changed

src/lightbox/LightboxActionSheet.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import share from './share';
55
import shareImage from './shareImage';
66
import { showToast } from '../utils/info';
77
import { getFullUrl } from '../utils/url';
8+
import tryGetTemporaryFileUrl from '../api/tryGetFileDownloadUrl';
9+
import openLink from '../utils/openLink';
810

911
type DownloadImageType = {|
1012
src: string,
@@ -33,8 +35,15 @@ type ButtonType = {|
3335
|};
3436

3537
const tryToDownloadImage = async ({ src, auth }: DownloadImageType) => {
38+
const tempUrl = await tryGetTemporaryFileUrl(src, auth);
39+
if (tempUrl === null) {
40+
showToast('Please download the image from your browser');
41+
openLink(src);
42+
return;
43+
}
44+
3645
try {
37-
await downloadImage(src, auth);
46+
await downloadImage(tempUrl, auth);
3847
showToast('Download complete');
3948
} catch (error) {
4049
showToast(error.message);

src/lightbox/downloadImage.js

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@ import { CameraRoll, Platform, PermissionsAndroid } from 'react-native';
33
import RNFetchBlob from 'rn-fetch-blob';
44

55
import type { Auth } from '../api/transportTypes';
6-
import { getAuthHeaders } from '../api/transport';
7-
import { getFullUrl } from '../utils/url';
8-
import userAgent from '../utils/userAgent';
96

107
/**
118
* Request permission WRITE_EXTERNAL_STORAGE, or throw if can't get it.
@@ -34,28 +31,27 @@ const androidEnsureStoragePermission = async (): Promise<void> => {
3431
// result === GRANTED
3532
};
3633

37-
export default async (src: string, auth: Auth): Promise<mixed> => {
38-
const absoluteUrl = getFullUrl(src, auth.realm);
39-
34+
/**
35+
* Download a remote image to the device.
36+
*
37+
* @param url A URL to the image. Should be a valid temporary URL generated
38+
* using `getTemporaryFileUrl`.
39+
* @param auth Authentication info for the current user.
40+
*/
41+
export default async (url: string, auth: Auth): Promise<mixed> => {
4042
if (Platform.OS === 'ios') {
41-
const delimiter = absoluteUrl.includes('?') ? '&' : '?';
42-
const urlWithApiKey = `${absoluteUrl}${delimiter}api_key=${auth.apiKey}`;
43-
return CameraRoll.saveToCameraRoll(urlWithApiKey);
43+
return CameraRoll.saveToCameraRoll(url);
4444
}
4545

4646
// Platform.OS === 'android'
4747
await androidEnsureStoragePermission();
4848
return RNFetchBlob.config({
4949
addAndroidDownloads: {
50-
path: `${RNFetchBlob.fs.dirs.DownloadDir}/${src.split('/').pop()}`,
50+
path: `${RNFetchBlob.fs.dirs.DownloadDir}/${url.split('/').pop()}`,
5151
useDownloadManager: true,
5252
mime: 'text/plain', // Android DownloadManager fails if the url is missing a file extension
53-
title: src.split('/').pop(),
53+
title: url.split('/').pop(),
5454
notification: true,
5555
},
56-
}).fetch('GET', absoluteUrl, {
57-
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
58-
'User-Agent': userAgent,
59-
...getAuthHeaders(auth),
60-
});
56+
}).fetch('GET', url);
6157
};

src/lightbox/shareImage.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,24 @@ import downloadImage from './downloadImage';
55
import type { Auth } from '../types';
66
import ShareImageAndroid from '../nativeModules/ShareImageAndroid';
77
import { showToast } from '../utils/info';
8+
import tryGetTemporaryFileUrl from '../api/tryGetFileDownloadUrl';
9+
import openLink from '../utils/openLink';
810

911
export default async (url: string, auth: Auth) => {
12+
const tempUrl = await tryGetTemporaryFileUrl(url, auth);
13+
14+
if (tempUrl === null) {
15+
showToast('Please share the image from your browser');
16+
openLink(url);
17+
return;
18+
}
19+
1020
if (Platform.OS === 'android') {
11-
const res: $FlowFixMe = await downloadImage(url, auth);
21+
const res: $FlowFixMe = await downloadImage(tempUrl, auth);
1222
await ShareImageAndroid.shareImage(res.path());
1323
} else {
1424
try {
15-
const uri = await downloadImage(url, auth);
25+
const uri = await downloadImage(tempUrl, auth);
1626
try {
1727
await Share.share({ url: uri, message: url });
1828
} catch (error) {

static/translations/messages_en.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,9 @@
182182
"Edit stream": "Edit stream",
183183
"OK": "OK",
184184
"Can not share": "Can not share",
185+
"Please share the image from your browser": "Please share the image from your browser",
185186
"Download complete": "Download complete",
187+
"Please download the image from your browser": "Please download the image from your browser",
186188
"Can not download": "Can not download",
187189
"Download file": "Download file",
188190
"Update": "Update",

0 commit comments

Comments
 (0)