Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ios/Discourse/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
<dict/>
</array>
<key>CFBundleVersion</key>
<string>700</string>
<string>705</string>
<key>Fabric</key>
<dict>
<key>APIKey</key>
Expand Down
185 changes: 109 additions & 76 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1648,6 +1648,35 @@ PODS:
- React-RCTFBReactNativeSpec
- ReactCommon/turbomodule/core
- SocketRocket
- react-native-blob-util (0.24.10):
- boost
- DoubleConversion
- fast_float
- fmt
- glog
- hermes-engine
- RCT-Folly
- RCT-Folly/Fabric
- RCTRequired
- RCTTypeSafety
- React-Core
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-hermes
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- react-native-blur (4.4.1):
- boost
- DoubleConversion
Expand Down Expand Up @@ -1776,7 +1805,7 @@ PODS:
- react-native-segmented-control (2.2.2):
- React-Core
- react-native-vector-icons-fontawesome5 (12.2.0)
- react-native-webview (13.17.0):
- react-native-webview (13.16.0):
- boost
- DoubleConversion
- fast_float
Expand Down Expand Up @@ -2722,6 +2751,7 @@ DEPENDENCIES:
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
- React-Mapbuffer (from `../node_modules/react-native/ReactCommon`)
- React-microtasksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`)
- react-native-blob-util (from `../node_modules/react-native-blob-util`)
- "react-native-blur (from `../node_modules/@react-native-community/blur`)"
- react-native-key-pair (from `../node_modules/react-native-key-pair`)
- react-native-safari-view (from `../node_modules/react-native-safari-view`)
Expand Down Expand Up @@ -2862,6 +2892,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon"
React-microtasksnativemodule:
:path: "../node_modules/react-native/ReactCommon/react/nativemodule/microtasks"
react-native-blob-util:
:path: "../node_modules/react-native-blob-util"
react-native-blur:
:path: "../node_modules/@react-native-community/blur"
react-native-key-pair:
Expand Down Expand Up @@ -2968,100 +3000,101 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/yoga"

SPEC CHECKSUMS:
boost: 1dca942403ed9342f98334bf4c3621f011aa7946
DoubleConversion: f16ae600a246532c4020132d54af21d0ddb2a385
boost: 7e761d76ca2ce687f7cc98e698152abd03a18f90
DoubleConversion: cb417026b2400c8f53ae97020b2be961b59470cb
fast_float: b32c788ed9c6a8c584d114d0047beda9664e7cc6
FBLazyVector: 86588b5a1547e7a417942a08f49559b184e002c8
fmt: 01b82d4ca6470831d1cc0852a1af644be019e8f6
glog: 08b301085f15bcbb6ff8632a8ebaf239aae04e6a
fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd
glog: 5683914934d5b6e4240e497e0f4a3b42d1854183
hermes-engine: bbc1152da7d2d40f9e59c28acc6576fcf5d28e2a
RCT-Folly: 846fda9475e61ec7bcbf8a3fe81edfcaeb090669
RCTDeprecation: 300c5eb91114d4339b0bb39505d0f4824d7299b7
RCTRequired: e0446b01093475b7082fbeee5d1ef4ad1fe20ac4
RCTTypeSafety: cb974efcdc6695deedf7bf1eb942f2a0603a063f
React: e7a4655b09d0e17e54be188cc34c2f3e2087318a
React-callinvoker: 62192daaa2f30c3321fc531e4f776f7b09cf892b
React-Core: b23cdaaa9d76389d958c06af3c57aa6ad611c542
React-CoreModules: 8e0f562e5695991e455abbebe1e968af71d52553
React-cxxreact: 6ccbe0cc2c652b29409b14b23cfb3cd74e084691
React-Core: c400b068fdb6172177f3b3fae00c10d1077244d7
React-CoreModules: 8e911a5a504b45824374eec240a78de7a6db8ca2
React-cxxreact: 06a91f55ac5f842219d6ca47e0f77187a5b5f4ac
React-debug: 1834225a63b420b16e9b8b01ba5870aee96d0610
React-defaultsnativemodule: dd88d445d542d58ab61a8a29a7c1d2272dfed577
React-domnativemodule: fc3c24f4d3bb92770727ea48b4133dab77ded7f7
React-Fabric: 00fe76339e568da0d0497cc72daeeb01e463871a
React-FabricComponents: 7bb179ee55db68f88c007800b0ac62c930115a85
React-FabricImage: 21e01118011dd1e4ff3cdab20dbf57839cff52ee
React-featureflags: 6e67f2e252bc8ebb1d538c2ae8c14df432fe5fc0
React-featureflagsnativemodule: eff5216a5cde5df5d09243d15db1bc401474deef
React-graphics: 8539372da8754118a565251ed08a88fc70f69340
React-hermes: cc8c77acee1406c258622cd8abbee9049f6b5761
React-idlecallbacksnativemodule: 7349675d1ccbec876c29b0e206ac08c762baaa36
React-ImageManager: 4089d8ad52c86a8ae1d7591282fff1665ff5518b
React-jserrorhandler: 89a7a5fa8d04791e729119d1db03bf0ee85a9e29
React-jsi: ea5c640ea63c127080f158dac7f4f393d13d415c
React-jsiexecutor: cf7920f82e46fe9a484c15c9f31e67d7179aa826
React-jsinspector: 69e974b6313dbbb635ba503f2f4f2c389b30edbf
React-jsinspectorcdp: 231ddd5b7164c37589dcde3b8b6960136c891d6d
React-jsinspectornetwork: ff74911f79cf0a407a7f0ad0eeb0be64687ed815
React-jsinspectortracing: df2aa2d944bb3fa280d9c920b9a06664bca8a7e8
React-jsitooling: 77849c27e374a028ed8106e434a35267f6c6600b
React-jsitracing: 0dc6978e5b38c6e5e01e6aed484e4aec3f5f581b
React-logger: 7cfc7b1ae1f8e5fe5097f9c746137cc3a8fad4ce
React-Mapbuffer: 7018c5b7da5b13ed22fe55dae51d50187a00b2d7
React-microtasksnativemodule: 8ff9cb220a8efa625b5885996bd69e69db9edf02
react-native-blur: 477fac85a42b5506232ef1d2b82aad359feadd26
react-native-key-pair: f69098449fa3f63baac4f4280910d4acb5ec3d89
react-native-safari-view: 07dc856a2663fef31eaca6beb79b111b8f6cf1f2
react-native-safari-web-auth: 63e920416493c35c795bae6b70fbda283497705e
react-native-safe-area-context: 8ed800930eb7d0b6651218f69656e823d37b6ef7
react-native-segmented-control: be570ddc1678933470a39471e0ebd824f23e39a8
React-defaultsnativemodule: 260aa990a9617c58df46c00321f396ad6ea7cc7f
React-domnativemodule: 9b3456a614c325da986867f27ca0eb34cb86828c
React-Fabric: fc7bcbac28989e6025ca6ae0988bff61bb78e5d3
React-FabricComponents: ae4a9c82bedf7c95bace1b215caf8685bcb32e23
React-FabricImage: c9cd4786180c150bb2a3841d65d360fd52be9ef8
React-featureflags: 534cd678e05848fbfc8c7288d4b14bcd8894b696
React-featureflagsnativemodule: bf7419f4d81226a3c4dd792445a03a6d703ce9a4
React-graphics: 18296c3559d54a42baaf7f2ae9c137a2e0fe9d51
React-hermes: b6e33fcd21aa7523dc76e62acd7a547e68c28a5b
React-idlecallbacksnativemodule: da8696a714ab16adb56bbfc9e0dfb4de7a713340
React-ImageManager: 052ccce122e4fd4e09c5d4f30e56381704dac439
React-jserrorhandler: 4c037384a32f57332abfa64181aeea915f9e0f0d
React-jsi: 3fde19aaf675c0607a0824c4d6002a4943820fd9
React-jsiexecutor: 4f898228240cf261a02568e985dfa7e1d7ad1dfb
React-jsinspector: 4ad0cdfa25a45d1362e2ddd06c78727d7964b34f
React-jsinspectorcdp: a649cc98a448e0fd8d54ac2a9e3e53177a1d8bd3
React-jsinspectornetwork: 2d701b6b152be202342f8269223046ec664c7d47
React-jsinspectortracing: cd898b3d7ea89f3e0ae10020fe3504bb4b327dd8
React-jsitooling: feca163583c69ba642cebb6b8ccd2f5e6732fed8
React-jsitracing: 1965307a468987b20d2a020f8fe782efa591ded7
React-logger: ea80169d826e0cd112fa4d68f58b2b3b968f1ecb
React-Mapbuffer: a5d550d1add940ed2bc65b20dc1413407bf1a63f
React-microtasksnativemodule: 5d00fefc19f0bc9a6432e5533683d6fc9c3da4e1
react-native-blob-util: 598a68ff8f2402eac074c54eac9a539238a5a222
react-native-blur: 736888dd75460ec75605254214caded098066cfc
react-native-key-pair: 5492baed2d7bbff57341ece66ecf5f5f340da439
react-native-safari-view: 955d7160d159241b8e9395d12d10ea0ef863dcdd
react-native-safari-web-auth: 73f4f00a0f1b6b1ad247e7e2b4ff7df5fe87a997
react-native-safe-area-context: fd72bd1eb562ff2a0fda20e9a7828c4b0cabf5a4
react-native-segmented-control: 65df6cd0619b780b3843d574a72d4c7cec396097
react-native-vector-icons-fontawesome5: 1199fa2cf3323fac0b9b52b2aecb1329aa3602a5
react-native-webview: a685ccea981f1410f67245117d44bfb91c6d7df6
React-NativeModulesApple: 37c08c3c54db55854de816b0df0f3683832be35a
react-native-webview: fe1b2ebf06ca1ba26e22caf7228abce5d9de4ec9
React-NativeModulesApple: b22e6abb44d78270dfdfc7d85efe29e35e0333a7
React-oscompat: 56d6de59f9ae95cd006a1c40be2cde83bc06a4e1
React-perflogger: 4008bd05a8b6c157b06608c0ea0b8bd5d9c5e6c9
React-performancetimeline: 9321ba7605abcfb3a2b497fd7cbaf5cfd8c7cf67
React-perflogger: 0633844e495d8b34798c9bf0cb32ce315f1d5c9f
React-performancetimeline: a04dae9154c32eda1891fcfa51cb2680a0421b3e
React-RCTActionSheet: 49138012280ec3bbb35193d8d09adb8bc61c982e
React-RCTAnimation: ebfe7c62016d4c17b56b2cab3a221908ae46288d
React-RCTAppDelegate: 0108657ba9a19f6a1cd62dcd19c2c0485b3fc251
React-RCTBlob: 6cc309d1623f3c2679125a04a7425685b7219e6b
React-RCTFabric: 0a9ff5c9d1e1d7fc026bda6671180cbf56861c15
React-RCTFBReactNativeSpec: ff3e37e2456afc04211334e86d07bf20488df0ae
React-RCTImage: bb98a59aeed953a48be3f917b9b745b213b340ab
React-RCTLinking: d6e9795d4d75d154c1dd821fd0746cc3e05d6670
React-RCTNetwork: 5c8a7a2dd26728323189362f149e788548ac72bc
React-RCTRuntime: 96808e8fdce300a26c82d8c24174e33ba5210a7c
React-RCTSettings: b6a02d545ce10dd936b39914b32674db6e865307
React-RCTText: c7d9232da0e9b5082a99a617483d9164a9cd46e9
React-RCTVibration: fe636c985c1bf25e4a5b5b4d9315a3b882468a72
React-RCTAnimation: c7ed4a9d5a4e43c9b10f68bb43cd238c4a2e7e89
React-RCTAppDelegate: ea2ab6f4aef1489f72025b7128d8ab645b40eafb
React-RCTBlob: c052799460b245e1fffe3d1dddea36fa88e998a0
React-RCTFabric: e7acf005f8ed58d09f755b980ff83703b3af9fcf
React-RCTFBReactNativeSpec: ffb22c3ee3d359ae9245ca94af203845da9371ec
React-RCTImage: 59fc2571f4f109a77139924f5babee8f9cd639c9
React-RCTLinking: a045cb58c08188dce6c6f4621de105114b1b16ce
React-RCTNetwork: fc7115a2f5e15ae0aa05e9a9be726817feefb482
React-RCTRuntime: a7bca9be4f571586b2a9d4b57cf605421ffb6335
React-RCTSettings: 30d7dd7eae66290467a1e72bf42d927fa78c3884
React-RCTText: 755d59284e66c7d33bb4f0ccc428fe69110c3e74
React-RCTVibration: ffe019e588815df226f6f8ccdc65979f8b2bc440
React-rendererconsistency: d20fcb77173861cc7d8356239823e3b36966fc31
React-renderercss: 56461d1e18db6a325048fdd04a51d68bd7ddb5a8
React-rendererdebug: fcd44d3eb8a02d74beee778bb142e724016c7375
React-renderercss: 63c720c32aaabd4788ac4136a071d49a052d8002
React-rendererdebug: a25ddddc73cabf50d814d8dfbc60d257b3d854c4
React-rncore: bafb76fc01b78757a9592e92dbc227f9260bf0ac
React-RuntimeApple: 01e3ad08793efaa54cf85276457fa4a1f103d5b4
React-RuntimeCore: 5c4bec5bf402a99b134e55972f2f4e676c70b9ab
React-RuntimeApple: 45f8ef1b220a91b4fa4a79820b81990bffd95aa5
React-RuntimeCore: a0e095493b22ee3f6c639df4258cc5185674f0b8
React-runtimeexecutor: b35de9cb7f5d19c66ea9b067235f95b947697ba5
React-RuntimeHermes: ba549a5834a6592d243b9a605530ecd7b6f5e79c
React-runtimescheduler: 9a9914d58caec7976aaae381cd2d997408f2260f
React-RuntimeHermes: 5b8126fffd1531475861dc0294a10b5f9793271a
React-runtimescheduler: 44fa97351d105afd0ffaecc4ed11cadad562deb6
React-timing: 4f97958cc918f0af9444f93e4a7083415e6f5daf
React-utils: f491e2726eb8ced8af13893e1f77317f0fa9a954
ReactAppDependencyProvider: 8df342c127fd0c1e30e8b9f71ff814c22414a7c0
ReactCodegen: 439c427ccc115d71d16cc84256e5fbdc7fcef57a
ReactCommon: 592ef441605638b95e533653259254b4bd35ff4f
RNBackgroundFetch: e44c9e85d7fb3122c37d8a806278f62c7682d7ea
RNCAsyncStorage: 579cd39b67a6eac3ffc4ebb45ad169b11b0f6fe7
RNCPushNotificationIOS: 6c4ca3388c7434e4a662b92e4dfeeee858e6f440
RNDeviceInfo: ae26ae45db3f9937f038a284bcd0a1db8d70db96
RNFlashList: e3c782f37970179e6b3c64f0f6007eb87d725f95
RNGestureHandler: db29d3e7edf41a11d133cc3ffd4029762376ed1a
RNLocalize: 8bf466de4c92d4721b254aabe1ff0a1456e7b9f4
RNReanimated: 5479b2116dcbbd2ba1eefb5561d5b322da306884
RNScreens: 26bb60cdb2ef2ca06fd87feefc495072f25982a7
RNSiriShortcuts: 149966f5de0cac63bd9fd8c2d5c51235439d1760
RNSVG: d407e5f2ede12bbcd92e4d23a405ad5a5f7294a3
RNWorklets: 83e051db94475b21fa729851b0d3aa523cd6f67a
React-utils: 3c4b0b7788e4dc132d1bf918bc0615e2b21f36b3
ReactAppDependencyProvider: 6c9197c1f6643633012ab646d2bfedd1b0d25989
ReactCodegen: 9ea66ee246511816b72e9d6e380f884b7b3b99d7
ReactCommon: 7aca047f2f453a7d7f0adeccb63810d61829235a
RNBackgroundFetch: 534f5bba01d1e45559aa7d53f42e00124378db93
RNCAsyncStorage: 8e9406ce79bba50a7ab965e1c05a93044f230de6
RNCPushNotificationIOS: 64218f3c776c03d7408284a819b2abfda1834bc8
RNDeviceInfo: 29e01d5ae94bdb5a0f6c11a4c438132545b4df80
RNFlashList: 995a7cad345dcb6f203db0f50bcf4b83cc04f3c9
RNGestureHandler: cdca641e24d0ab743dcd90a24de4e6259e6aa0de
RNLocalize: d4b8af4e442d4bcca54e68fc687a2129b4d71a81
RNReanimated: 3d16d7db5b36d76df0477df0723d28d2235c97f8
RNScreens: 45e1adbc3b4bab2900bf9bb9decfcfb59d0eed8c
RNSiriShortcuts: 17f5bcb1322eb9e9387101110db1cdb6ed82707c
RNSVG: 432ca012e24410cab11449afef353ce20573a59f
RNWorklets: a45d7a51e3c1f50e4d5cc73a1d11d34b76c843b4
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
Yoga: a742cc68e8366fcfc681808162492bc0aa7a9498

PODFILE CHECKSUM: 8125ac004090fc2c53beddf13d18c2becd0d99e9

COCOAPODS: 1.16.2
COCOAPODS: 1.15.2
2 changes: 1 addition & 1 deletion ios/ShareExtension/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<key>CFBundleShortVersionString</key>
<string>2.2.3</string>
<key>CFBundleVersion</key>
<string>700</string>
<string>705</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
Expand Down
95 changes: 95 additions & 0 deletions js/lib/__tests__/handleDownload.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/* @flow */
'use strict';

import { Alert, Platform, Share, ToastAndroid } from 'react-native';
import ReactNativeBlobUtil from 'react-native-blob-util';
import handleDownload, {
MAX_BRIDGED_DOWNLOAD_BYTES,
sanitizeFilename,
validateDownloadMessage,
} from '../handleDownload';

jest.mock('i18n-js', () => ({
t: (key, params) => (params?.filename ? `${key}:${params.filename}` : key),
}));

jest.mock('react-native-blob-util', () => ({
fs: {
dirs: { CacheDir: '/cache' },
writeFile: jest.fn(() => Promise.resolve()),
unlink: jest.fn(() => Promise.resolve()),
},
MediaCollection: {
copyToMediaStore: jest.fn(() => Promise.resolve()),
},
}));

function message(overrides = {}) {
return {
type: 'download',
version: 1,
encoding: 'base64',
filename: 'theme.zip',
mimeType: 'application/zip',
byteLength: 1,
data: 'eA==',
...overrides,
};
}

describe('handleDownload', () => {
beforeEach(() => {
jest.clearAllMocks();
Platform.OS = 'ios';
Share.share = jest.fn(() => Promise.resolve());
Alert.alert = jest.fn();
ToastAndroid.show = jest.fn();
});

test('sanitizes filenames used in native paths', () => {
expect(sanitizeFilename('../../bad\\name:\u0000.zip')).toBe(
'_.._bad_name.zip',
);
expect(sanitizeFilename('...')).toBe('download');
});

test('rejects malformed and oversized messages', () => {
expect(() =>
validateDownloadMessage(message({ data: 'not base64' })),
).toThrow('Invalid download data');
expect(() =>
validateDownloadMessage(
message({ byteLength: MAX_BRIDGED_DOWNLOAD_BYTES + 1 }),
),
).toThrow('Download is too large');
});

test('writes, shares, and removes an iOS temporary file', async () => {
await handleDownload(message());

expect(ReactNativeBlobUtil.fs.writeFile).toHaveBeenCalledWith(
expect.stringMatching(/^\/cache\/.+-theme\.zip$/),
'eA==',
'base64',
);
expect(Share.share).toHaveBeenCalledWith(
expect.objectContaining({ title: 'theme.zip' }),
);
expect(ReactNativeBlobUtil.fs.unlink).toHaveBeenCalled();
expect(Alert.alert).not.toHaveBeenCalled();
});

test('removes the temporary file and reports native failures', async () => {
ReactNativeBlobUtil.fs.writeFile.mockRejectedValueOnce(
new Error('disk full'),
);

await handleDownload(message());

expect(ReactNativeBlobUtil.fs.unlink).toHaveBeenCalled();
expect(Alert.alert).toHaveBeenCalledWith(
'download.failed_title',
'disk full',
);
});
});
Loading
Loading