From d51c7fc0383257b8cc65c586b97d4f2ecbd80d13 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Thu, 23 Feb 2023 10:25:38 +0100 Subject: [PATCH 01/15] Add base64-js vendor --- src/js/vendor/base64-js/LICENSE | 21 ++++++++ src/js/vendor/base64-js/fromByteArray.ts | 68 ++++++++++++++++++++++++ src/js/vendor/base64-js/index.ts | 3 ++ src/js/vendor/index.ts | 4 ++ test/vendor/base64-js/big-data.test.ts | 17 ++++++ test/vendor/base64-js/convert.test.ts | 63 ++++++++++++++++++++++ 6 files changed, 176 insertions(+) create mode 100644 src/js/vendor/base64-js/LICENSE create mode 100644 src/js/vendor/base64-js/fromByteArray.ts create mode 100644 src/js/vendor/base64-js/index.ts create mode 100644 test/vendor/base64-js/big-data.test.ts create mode 100644 test/vendor/base64-js/convert.test.ts diff --git a/src/js/vendor/base64-js/LICENSE b/src/js/vendor/base64-js/LICENSE new file mode 100644 index 000000000..6d52b8acf --- /dev/null +++ b/src/js/vendor/base64-js/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Jameson Little + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/js/vendor/base64-js/fromByteArray.ts b/src/js/vendor/base64-js/fromByteArray.ts new file mode 100644 index 000000000..fd2e3d3d1 --- /dev/null +++ b/src/js/vendor/base64-js/fromByteArray.ts @@ -0,0 +1,68 @@ +/* eslint-disable */ + +// https://github.dev/beatgammit/base64-js/blob/88957c9943c7e2a0f03cdf73e71d579e433627d3/index.js#L119 +// License: MIT + +const lookup: string[] = [] + +const code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' +for (let i = 0, len = code.length; i < len; ++i) { + lookup[i] = code[i] +} + +function tripletToBase64(num: number): string { + return lookup[num >> 18 & 0x3F] + + lookup[num >> 12 & 0x3F] + + lookup[num >> 6 & 0x3F] + + lookup[num & 0x3F] +} + +function encodeChunk(uint8: Uint8Array | number[], start: number, end: number): string { + let tmp + const output = [] + for (let i = start; i < end; i += 3) { + tmp = + ((uint8[i] << 16) & 0xFF0000) + + ((uint8[i + 1] << 8) & 0xFF00) + + (uint8[i + 2] & 0xFF) + output.push(tripletToBase64(tmp)) + } + // console.log('encodeChunk', output.length, uint8.length, start, end); + return output.join('') +} + +/** + * + */ +export function fromByteArray(uint8: Uint8Array | number[]): string { + let tmp + const len = uint8.length + const extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes + const parts = [] + const maxChunkLength = 16383 // must be multiple of 3 + + // go through the array every three bytes, we'll deal with trailing stuff later + for (let i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { + parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))) + } + + // pad the end with zeros, but make sure to not forget the extra bytes + if (extraBytes === 1) { + tmp = uint8[len - 1] + parts.push( + `${lookup[tmp >> 2] + + lookup[(tmp << 4) & 0x3F] + }==` + ) + } else if (extraBytes === 2) { + tmp = (uint8[len - 2] << 8) + uint8[len - 1] + parts.push( + `${lookup[tmp >> 10] + + lookup[(tmp >> 4) & 0x3F] + + lookup[(tmp << 2) & 0x3F] + }=` + ) + } + + return parts.join('') +} diff --git a/src/js/vendor/base64-js/index.ts b/src/js/vendor/base64-js/index.ts new file mode 100644 index 000000000..7602cd1c3 --- /dev/null +++ b/src/js/vendor/base64-js/index.ts @@ -0,0 +1,3 @@ +export { + fromByteArray, +} from './fromByteArray'; diff --git a/src/js/vendor/index.ts b/src/js/vendor/index.ts index becf74c14..7225fa100 100644 --- a/src/js/vendor/index.ts +++ b/src/js/vendor/index.ts @@ -2,3 +2,7 @@ export { utf8ToBytes, } from './buffer'; + +export { + fromByteArray, +} from './base64-js'; diff --git a/test/vendor/base64-js/big-data.test.ts b/test/vendor/base64-js/big-data.test.ts new file mode 100644 index 000000000..9314441d6 --- /dev/null +++ b/test/vendor/base64-js/big-data.test.ts @@ -0,0 +1,17 @@ +// https://github.dev/beatgammit/base64-js/blob/88957c9943c7e2a0f03cdf73e71d579e433627d3/test/big-data.js#L4 +// License: MIT + +import { fromByteArray } from '../../../src/js/vendor' + +describe('base64-js', () => { + test('convert big data to base64', () => { + const SIZE_2MB = 2e6; // scaled down from original 64MiB + const big = new Uint8Array(SIZE_2MB); + for (let i = 0, length = big.length; i < length; ++i) { + big[i] = i % 256 + } + const b64str = fromByteArray(big) + const arr = Uint8Array.from(Buffer.from(b64str, 'base64')) + expect(arr).toEqual(big) + }) +}); diff --git a/test/vendor/base64-js/convert.test.ts b/test/vendor/base64-js/convert.test.ts new file mode 100644 index 000000000..9acdabe96 --- /dev/null +++ b/test/vendor/base64-js/convert.test.ts @@ -0,0 +1,63 @@ +// https://github.dev/beatgammit/base64-js/blob/88957c9943c7e2a0f03cdf73e71d579e433627d3/test/convert.js#L15 +// License: MIT + +import { fromByteArray } from '../../../src/js/vendor' + +describe('base64-js', () => { + const checks = [ + 'a', + 'aa', + 'aaa', + 'hi', + 'hi!', + 'hi!!', + 'sup', + 'sup?', + 'sup?!' + ] + + test('convert to base64 and back', () => { + for (const check of checks) { + const b64Str = fromByteArray(map(check, function (char: string) { return char.charCodeAt(0) })) + + const str = Buffer.from(b64Str, 'base64').toString() + + expect(check).toEqual(str) + } + }) + + const data: [number[], string][] = [ + [[0, 0, 0], 'AAAA'], + [[0, 0, 1], 'AAAB'], + [[0, 1, -1], 'AAH/'], + [[1, 1, 1], 'AQEB'], + [[0, -73, 23], 'ALcX'] + ] + + test('convert known data to string', () => { + for (const check of data) { + const bytes = check[0] + const expected = check[1] + const actual = fromByteArray(bytes) + expect(actual).toEqual(expected) + } + }) + + function map(arr: string, callback: (char: string) => number): number[] { + const res = [] + let kValue, mappedValue + + for (let k = 0, len = arr.length; k < len; k++) { + if ((typeof arr === 'string' && !!arr.charAt(k))) { + kValue = arr.charAt(k) + mappedValue = callback(kValue) + res[k] = mappedValue + } else if (typeof arr !== 'string' && k in arr) { + kValue = arr[k] + mappedValue = callback(kValue) + res[k] = mappedValue + } + } + return res + } +}); From f5aab6e81a711d5951be000c43e3a89ac457a9a9 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Thu, 23 Feb 2023 10:31:27 +0100 Subject: [PATCH 02/15] Change Spec of NativeRNSentry --- src/js/NativeRNSentry.ts | 2 +- src/js/wrapper.ts | 4 ++-- test/wrapper.test.ts | 26 +++++++++++++------------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/js/NativeRNSentry.ts b/src/js/NativeRNSentry.ts index c4380faf5..75c0c66a3 100644 --- a/src/js/NativeRNSentry.ts +++ b/src/js/NativeRNSentry.ts @@ -8,7 +8,7 @@ import type { UnsafeObject } from 'react-native/Libraries/Types/CodegenTypes'; export interface Spec extends TurboModule { addBreadcrumb(breadcrumb: UnsafeObject): void; captureEnvelope( - bytes: number[], + bytes: string, options: { store: boolean, }, diff --git a/src/js/wrapper.ts b/src/js/wrapper.ts index b4c90e823..8288f548c 100644 --- a/src/js/wrapper.ts +++ b/src/js/wrapper.ts @@ -24,7 +24,7 @@ import type { import type { ReactNativeOptions } from './options'; import type { RequiredKeysUser } from './user'; import { isTurboModuleEnabled } from './utils/environment' -import { utf8ToBytes } from './vendor'; +import { fromByteArray, utf8ToBytes } from './vendor'; const RNSentry: Spec | undefined = isTurboModuleEnabled() ? TurboModuleRegistry.getEnforcing('RNSentry') @@ -156,7 +156,7 @@ export const NATIVE: SentryNativeWrapper = { envelopeBytes.push(EOL); } - await RNSentry.captureEnvelope(envelopeBytes, { store: hardCrashed }); + await RNSentry.captureEnvelope(fromByteArray(envelopeBytes), { store: hardCrashed }); }, /** diff --git a/test/wrapper.test.ts b/test/wrapper.test.ts index c262985dd..02e542f74 100644 --- a/test/wrapper.test.ts +++ b/test/wrapper.test.ts @@ -5,7 +5,7 @@ import * as RN from 'react-native'; import type { Spec } from '../src/js/NativeRNSentry'; import type { ReactNativeOptions } from '../src/js/options'; -import { utf8ToBytes } from '../src/js/vendor'; +import { fromByteArray, utf8ToBytes } from '../src/js/vendor'; import { NATIVE } from '../src/js/wrapper'; jest.mock( @@ -215,10 +215,10 @@ describe('Tests Native Wrapper', () => { await NATIVE.sendEnvelope(env); expect(RNSentry.captureEnvelope).toBeCalledWith( - utf8ToBytes('{"event_id":"event0","sent_at":"123"}\n' + fromByteArray(utf8ToBytes('{"event_id":"event0","sent_at":"123"}\n' + '{"type":"event","content_type":"application/json","length":87}\n' + '{"event_id":"event0","message":"test","sdk":{"name":"test-sdk-name","version":"2.1.3"}}\n' - ), + )), { store: false }, ); }); @@ -244,10 +244,10 @@ describe('Tests Native Wrapper', () => { await NATIVE.sendEnvelope(env); expect(RNSentry.captureEnvelope).toBeCalledWith( - utf8ToBytes('{"event_id":"event0","sent_at":"123"}\n' + fromByteArray(utf8ToBytes('{"event_id":"event0","sent_at":"123"}\n' + '{"type":"event","content_type":"application/json","length":93}\n' + '{"event_id":"event0","sdk":{"name":"test-sdk-name","version":"2.1.3"},"instance":{"value":0}}\n' - ), + )), { store: false }, ); }); @@ -279,10 +279,10 @@ describe('Tests Native Wrapper', () => { await NATIVE.sendEnvelope(env); expect(RNSentry.captureEnvelope).toBeCalledWith( - utf8ToBytes('{"event_id":"event0","sent_at":"123"}\n' + fromByteArray(utf8ToBytes('{"event_id":"event0","sent_at":"123"}\n' + '{"type":"event","content_type":"application/json","length":50}\n' + '{"event_id":"event0","message":{"message":"test"}}\n' - ), + )), { store: false }, ); }); @@ -315,10 +315,10 @@ describe('Tests Native Wrapper', () => { await NATIVE.sendEnvelope(env); expect(RNSentry.captureEnvelope).toBeCalledWith( - utf8ToBytes('{"event_id":"event0","sent_at":"123"}\n' + fromByteArray(utf8ToBytes('{"event_id":"event0","sent_at":"123"}\n' + '{"type":"event","content_type":"application/json","length":104}\n' + '{"event_id":"event0","exception":{"values":[{"mechanism":{"handled":true,"type":""}}]},"breadcrumbs":[]}\n' - ), + )), { store: false }, ); }); @@ -341,10 +341,10 @@ describe('Tests Native Wrapper', () => { await NATIVE.sendEnvelope(env); expect(RNSentry.captureEnvelope).toBeCalledWith( - utf8ToBytes('{"event_id":"event0","sent_at":"123"}\n' + fromByteArray(utf8ToBytes('{"event_id":"event0","sent_at":"123"}\n' + '{"type":"event","content_type":"application/json","length":38}\n' + '{"event_id":"event0","breadcrumbs":[]}\n' - ), + )), { store: false }, ); }); @@ -377,10 +377,10 @@ describe('Tests Native Wrapper', () => { await NATIVE.sendEnvelope(env); expect(RNSentry.captureEnvelope).toBeCalledWith( - utf8ToBytes('{"event_id":"event0","sent_at":"123"}\n' + fromByteArray(utf8ToBytes('{"event_id":"event0","sent_at":"123"}\n' + '{"type":"event","content_type":"application/json","length":125}\n' + '{"event_id":"event0","exception":{"values":[{"mechanism":{"handled":false,"type":""}}]},"breadcrumbs":[{"message":"crumb!"}]}\n' - ), + )), { store: true }, ); }); From d020d9f4c3ce4f3a50b43fb1677204f168e27e51 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Thu, 23 Feb 2023 10:34:09 +0100 Subject: [PATCH 03/15] Use typed array to store envelope bytes --- src/js/wrapper.ts | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/js/wrapper.ts b/src/js/wrapper.ts index 8288f548c..4bac8fcf9 100644 --- a/src/js/wrapper.ts +++ b/src/js/wrapper.ts @@ -83,6 +83,8 @@ interface SentryNativeWrapper { fetchViewHierarchy(): PromiseLike; } +const EOL = utf8ToBytes('\n'); + /** * Our internal interface for calling native functions */ @@ -115,20 +117,20 @@ export const NATIVE: SentryNativeWrapper = { throw this._NativeClientError; } - const [EOL] = utf8ToBytes('\n'); - const [envelopeHeader, envelopeItems] = envelope; const headerString = JSON.stringify(envelopeHeader); - let envelopeBytes: number[] = utf8ToBytes(headerString); - envelopeBytes.push(EOL); + const headerBytes = utf8ToBytes(headerString); + let envelopeBytes: Uint8Array = new Uint8Array(headerBytes.length + EOL.length); + envelopeBytes.set(headerBytes); + envelopeBytes.set(EOL, headerBytes.length); let hardCrashed: boolean = false; for (const rawItem of envelopeItems) { const [itemHeader, itemPayload] = this._processItem(rawItem); let bytesContentType: string; - let bytesPayload: number[] = []; + let bytesPayload: number[] | Uint8Array | undefined; if (typeof itemPayload === 'string') { bytesContentType = 'text/plain'; bytesPayload = utf8ToBytes(itemPayload); @@ -136,7 +138,7 @@ export const NATIVE: SentryNativeWrapper = { bytesContentType = typeof itemHeader.content_type === 'string' ? itemHeader.content_type : 'application/octet-stream'; - bytesPayload = [...itemPayload]; + bytesPayload = itemPayload; } else { bytesContentType = 'application/json'; bytesPayload = utf8ToBytes(JSON.stringify(itemPayload)); @@ -150,10 +152,16 @@ export const NATIVE: SentryNativeWrapper = { (itemHeader as BaseEnvelopeItemHeaders).length = bytesPayload.length; const serializedItemHeader = JSON.stringify(itemHeader); - envelopeBytes.push(...utf8ToBytes(serializedItemHeader)); - envelopeBytes.push(EOL); - envelopeBytes = envelopeBytes.concat(bytesPayload); - envelopeBytes.push(EOL); + const bytesItemHeader = utf8ToBytes(serializedItemHeader); + const newBytes = new Uint8Array( + envelopeBytes.length + bytesItemHeader.length + EOL.length + bytesPayload.length + EOL.length, + ); + newBytes.set(envelopeBytes); + newBytes.set(bytesItemHeader, envelopeBytes.length); + newBytes.set(EOL, envelopeBytes.length + bytesItemHeader.length); + newBytes.set(bytesPayload, envelopeBytes.length + bytesItemHeader.length + EOL.length); + newBytes.set(EOL, envelopeBytes.length + bytesItemHeader.length + EOL.length + bytesPayload.length); + envelopeBytes = newBytes; } await RNSentry.captureEnvelope(fromByteArray(envelopeBytes), { store: hardCrashed }); From 88392c1cdf83c01b540ba458793bde897f22917c Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Thu, 23 Feb 2023 10:35:11 +0100 Subject: [PATCH 04/15] Switch android to base64 envelopes --- .../src/main/java/io/sentry/react/RNSentryModuleImpl.java | 8 +++----- .../src/newarch/java/io/sentry/react/RNSentryModule.java | 2 +- .../src/oldarch/java/io/sentry/react/RNSentryModule.java | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java b/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java index f96c83967..c52bf7186 100644 --- a/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java +++ b/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java @@ -62,6 +62,7 @@ import io.sentry.protocol.User; import io.sentry.protocol.ViewHierarchy; import io.sentry.util.JsonSerializationUtils; +import io.sentry.vendor.Base64; public class RNSentryModuleImpl { @@ -314,11 +315,8 @@ public void fetchNativeFrames(Promise promise) { } } - public void captureEnvelope(ReadableArray rawBytes, ReadableMap options, Promise promise) { - byte[] bytes = new byte[rawBytes.size()]; - for (int i = 0; i < rawBytes.size(); i++) { - bytes[i] = (byte) rawBytes.getInt(i); - } + public void captureEnvelope(String rawBytes, ReadableMap options, Promise promise) { + byte[] bytes = Base64.decode(rawBytes, Base64.DEFAULT); try { final String outboxPath = HubAdapter.getInstance().getOptions().getOutboxPath(); diff --git a/android/src/newarch/java/io/sentry/react/RNSentryModule.java b/android/src/newarch/java/io/sentry/react/RNSentryModule.java index 40eb787b1..0838eee1f 100644 --- a/android/src/newarch/java/io/sentry/react/RNSentryModule.java +++ b/android/src/newarch/java/io/sentry/react/RNSentryModule.java @@ -53,7 +53,7 @@ public void fetchNativeFrames(Promise promise) { } @Override - public void captureEnvelope(ReadableArray rawBytes, ReadableMap options, Promise promise) { + public void captureEnvelope(String rawBytes, ReadableMap options, Promise promise) { this.impl.captureEnvelope(rawBytes, options, promise); } diff --git a/android/src/oldarch/java/io/sentry/react/RNSentryModule.java b/android/src/oldarch/java/io/sentry/react/RNSentryModule.java index c1f09c5c4..d70da11eb 100644 --- a/android/src/oldarch/java/io/sentry/react/RNSentryModule.java +++ b/android/src/oldarch/java/io/sentry/react/RNSentryModule.java @@ -53,7 +53,7 @@ public void fetchNativeFrames(Promise promise) { } @ReactMethod - public void captureEnvelope(ReadableArray rawBytes, ReadableMap options, Promise promise) { + public void captureEnvelope(String rawBytes, ReadableMap options, Promise promise) { this.impl.captureEnvelope(rawBytes, options, promise); } From 00dbaef1e4bc3790b85c83286473db1ce38a2582 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Thu, 23 Feb 2023 11:09:37 +0100 Subject: [PATCH 05/15] Switch iOS to base64 envelopes --- ios/RNSentry.mm | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ios/RNSentry.mm b/ios/RNSentry.mm index 80db9de99..532a5bef0 100644 --- a/ios/RNSentry.mm +++ b/ios/RNSentry.mm @@ -278,16 +278,12 @@ - (void)setEventEnvironmentTag:(SentryEvent *)event }); } -RCT_EXPORT_METHOD(captureEnvelope:(NSArray * _Nonnull)bytes +RCT_EXPORT_METHOD(captureEnvelope:(NSString * _Nonnull)bytes options: (NSDictionary * _Nonnull)options resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { - NSMutableData *data = [[NSMutableData alloc] initWithCapacity: [bytes count]]; - for(NSNumber *number in bytes) { - char byte = [number charValue]; - [data appendBytes: &byte length: 1]; - } + NSData *data = [[NSData alloc] initWithBase64EncodedString:bytes options:0]; SentryEnvelope *envelope = [PrivateSentrySDKOnly envelopeWithData:data]; if (envelope == nil) { From a704d11e055a0d2f3687255144feb8893a32c95d Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Thu, 23 Feb 2023 11:26:01 +0100 Subject: [PATCH 06/15] Add changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7fef15e6..a1436ab02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## Unreleased + +### Fixes + +- Capture large envelopes (10s of MB) correctly. ([#2708](https://github.com/getsentry/sentry-react-native/pull/2708)) + - Note that this fix require rebuild of the native app + ## 5.0.0 The React Native SDK version 5 supports both Legacy (from RN 0.65 and above) and New Architecture (from RN 0.69 and above) as well as the new React Native Gradle Plugin (introduced in RN 0.71). For detailed [migration guide visit our docs](https://docs.sentry.io/platforms/react-native/migration/#from-4x-to-5x). From 272756f7ee2fd1b7fc053475a76f8da4d1d9c89b Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Thu, 23 Feb 2023 11:29:30 +0100 Subject: [PATCH 07/15] Fix changelog pr id --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1436ab02..a2e0db2de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Fixes -- Capture large envelopes (10s of MB) correctly. ([#2708](https://github.com/getsentry/sentry-react-native/pull/2708)) +- Capture large envelopes (10s of MB) correctly. ([#2852](https://github.com/getsentry/sentry-react-native/pull/2852)) - Note that this fix require rebuild of the native app ## 5.0.0 From 0c875926beeba722d4e4a684641656eaf19377da Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Thu, 23 Feb 2023 11:31:05 +0100 Subject: [PATCH 08/15] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2e0db2de..1aed2c31a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ ### Fixes - Capture large envelopes (10s of MB) correctly. ([#2852](https://github.com/getsentry/sentry-react-native/pull/2852)) - - Note that this fix require rebuild of the native app + - Note that this fix requires a rebuild of the native app ## 5.0.0 From 1887b193b628c812ec7bacb9ff01e05984e74587 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 15 May 2023 10:22:21 +0200 Subject: [PATCH 09/15] Fix lint and licenses --- src/js/vendor/base64-js/LICENSE | 21 ------ src/js/vendor/base64-js/fromByteArray.ts | 80 +++++++++++----------- src/js/vendor/base64-js/index.ts | 4 +- src/js/vendor/index.ts | 9 +-- src/js/wrapper.ts | 2 +- test/vendor/base64-js/big-data.test.ts | 37 ++++++++--- test/vendor/base64-js/convert.test.ts | 85 ++++++++++++++---------- test/wrapper.test.ts | 66 +++++++++++------- 8 files changed, 168 insertions(+), 136 deletions(-) delete mode 100644 src/js/vendor/base64-js/LICENSE diff --git a/src/js/vendor/base64-js/LICENSE b/src/js/vendor/base64-js/LICENSE deleted file mode 100644 index 6d52b8acf..000000000 --- a/src/js/vendor/base64-js/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Jameson Little - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/src/js/vendor/base64-js/fromByteArray.ts b/src/js/vendor/base64-js/fromByteArray.ts index fd2e3d3d1..01a02d655 100644 --- a/src/js/vendor/base64-js/fromByteArray.ts +++ b/src/js/vendor/base64-js/fromByteArray.ts @@ -1,68 +1,74 @@ /* eslint-disable */ -// https://github.dev/beatgammit/base64-js/blob/88957c9943c7e2a0f03cdf73e71d579e433627d3/index.js#L119 -// License: MIT +// Adapted from https://github.dev/beatgammit/base64-js/blob/88957c9943c7e2a0f03cdf73e71d579e433627d3/index.js#L119 -const lookup: string[] = [] +// The MIT License (MIT) -const code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' +// Copyright (c) 2014 Jameson Little + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +const lookup: string[] = []; + +const code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; for (let i = 0, len = code.length; i < len; ++i) { - lookup[i] = code[i] + lookup[i] = code[i]; } function tripletToBase64(num: number): string { - return lookup[num >> 18 & 0x3F] + - lookup[num >> 12 & 0x3F] + - lookup[num >> 6 & 0x3F] + - lookup[num & 0x3F] + return lookup[(num >> 18) & 0x3f] + lookup[(num >> 12) & 0x3f] + lookup[(num >> 6) & 0x3f] + lookup[num & 0x3f]; } function encodeChunk(uint8: Uint8Array | number[], start: number, end: number): string { - let tmp - const output = [] + let tmp; + const output = []; for (let i = start; i < end; i += 3) { - tmp = - ((uint8[i] << 16) & 0xFF0000) + - ((uint8[i + 1] << 8) & 0xFF00) + - (uint8[i + 2] & 0xFF) - output.push(tripletToBase64(tmp)) + tmp = ((uint8[i] << 16) & 0xff0000) + ((uint8[i + 1] << 8) & 0xff00) + (uint8[i + 2] & 0xff); + output.push(tripletToBase64(tmp)); } // console.log('encodeChunk', output.length, uint8.length, start, end); - return output.join('') + return output.join(''); } /** * */ export function fromByteArray(uint8: Uint8Array | number[]): string { - let tmp - const len = uint8.length - const extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes - const parts = [] - const maxChunkLength = 16383 // must be multiple of 3 + let tmp; + const len = uint8.length; + const extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes + const parts = []; + const maxChunkLength = 16383; // must be multiple of 3 // go through the array every three bytes, we'll deal with trailing stuff later for (let i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { - parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))) + parts.push(encodeChunk(uint8, i, i + maxChunkLength > len2 ? len2 : i + maxChunkLength)); } // pad the end with zeros, but make sure to not forget the extra bytes if (extraBytes === 1) { - tmp = uint8[len - 1] - parts.push( - `${lookup[tmp >> 2] + - lookup[(tmp << 4) & 0x3F] - }==` - ) + tmp = uint8[len - 1]; + parts.push(`${lookup[tmp >> 2] + lookup[(tmp << 4) & 0x3f]}==`); } else if (extraBytes === 2) { - tmp = (uint8[len - 2] << 8) + uint8[len - 1] - parts.push( - `${lookup[tmp >> 10] + - lookup[(tmp >> 4) & 0x3F] + - lookup[(tmp << 2) & 0x3F] - }=` - ) + tmp = (uint8[len - 2] << 8) + uint8[len - 1]; + parts.push(`${lookup[tmp >> 10] + lookup[(tmp >> 4) & 0x3f] + lookup[(tmp << 2) & 0x3f]}=`); } - return parts.join('') + return parts.join(''); } diff --git a/src/js/vendor/base64-js/index.ts b/src/js/vendor/base64-js/index.ts index 7602cd1c3..63a97c19b 100644 --- a/src/js/vendor/base64-js/index.ts +++ b/src/js/vendor/base64-js/index.ts @@ -1,3 +1 @@ -export { - fromByteArray, -} from './fromByteArray'; +export { fromByteArray } from './fromByteArray'; diff --git a/src/js/vendor/index.ts b/src/js/vendor/index.ts index 7225fa100..88713f48b 100644 --- a/src/js/vendor/index.ts +++ b/src/js/vendor/index.ts @@ -1,8 +1,3 @@ +export { utf8ToBytes } from './buffer'; -export { - utf8ToBytes, -} from './buffer'; - -export { - fromByteArray, -} from './base64-js'; +export { fromByteArray } from './base64-js'; diff --git a/src/js/wrapper.ts b/src/js/wrapper.ts index 6c57f9a85..3ab298bf2 100644 --- a/src/js/wrapper.ts +++ b/src/js/wrapper.ts @@ -23,7 +23,7 @@ import type { } from './NativeRNSentry'; import type { ReactNativeClientOptions } from './options'; import type { RequiredKeysUser } from './user'; -import { isTurboModuleEnabled } from './utils/environment' +import { isTurboModuleEnabled } from './utils/environment'; import { fromByteArray, utf8ToBytes } from './vendor'; const RNSentry: Spec | undefined = isTurboModuleEnabled() diff --git a/test/vendor/base64-js/big-data.test.ts b/test/vendor/base64-js/big-data.test.ts index 9314441d6..3b9ec5a7a 100644 --- a/test/vendor/base64-js/big-data.test.ts +++ b/test/vendor/base64-js/big-data.test.ts @@ -1,17 +1,38 @@ -// https://github.dev/beatgammit/base64-js/blob/88957c9943c7e2a0f03cdf73e71d579e433627d3/test/big-data.js#L4 -// License: MIT +// Adapted from https://github.dev/beatgammit/base64-js/blob/88957c9943c7e2a0f03cdf73e71d579e433627d3/test/big-data.js#L4 -import { fromByteArray } from '../../../src/js/vendor' +// The MIT License (MIT) + +// Copyright (c) 2014 Jameson Little + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import { fromByteArray } from '../../../src/js/vendor'; describe('base64-js', () => { test('convert big data to base64', () => { const SIZE_2MB = 2e6; // scaled down from original 64MiB const big = new Uint8Array(SIZE_2MB); for (let i = 0, length = big.length; i < length; ++i) { - big[i] = i % 256 + big[i] = i % 256; } - const b64str = fromByteArray(big) - const arr = Uint8Array.from(Buffer.from(b64str, 'base64')) - expect(arr).toEqual(big) - }) + const b64str = fromByteArray(big); + const arr = Uint8Array.from(Buffer.from(b64str, 'base64')); + expect(arr).toEqual(big); + }); }); diff --git a/test/vendor/base64-js/convert.test.ts b/test/vendor/base64-js/convert.test.ts index 9acdabe96..c2e63713a 100644 --- a/test/vendor/base64-js/convert.test.ts +++ b/test/vendor/base64-js/convert.test.ts @@ -1,63 +1,78 @@ -// https://github.dev/beatgammit/base64-js/blob/88957c9943c7e2a0f03cdf73e71d579e433627d3/test/convert.js#L15 -// License: MIT +// Adapted from https://github.dev/beatgammit/base64-js/blob/88957c9943c7e2a0f03cdf73e71d579e433627d3/test/convert.js#L15 -import { fromByteArray } from '../../../src/js/vendor' +// The MIT License (MIT) + +// Copyright (c) 2014 Jameson Little + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import { fromByteArray } from '../../../src/js/vendor'; describe('base64-js', () => { - const checks = [ - 'a', - 'aa', - 'aaa', - 'hi', - 'hi!', - 'hi!!', - 'sup', - 'sup?', - 'sup?!' - ] + const checks = ['a', 'aa', 'aaa', 'hi', 'hi!', 'hi!!', 'sup', 'sup?', 'sup?!']; test('convert to base64 and back', () => { for (const check of checks) { - const b64Str = fromByteArray(map(check, function (char: string) { return char.charCodeAt(0) })) + const b64Str = fromByteArray( + map(check, function (char: string) { + return char.charCodeAt(0); + }), + ); - const str = Buffer.from(b64Str, 'base64').toString() + const str = Buffer.from(b64Str, 'base64').toString(); - expect(check).toEqual(str) + expect(check).toEqual(str); } - }) + }); const data: [number[], string][] = [ [[0, 0, 0], 'AAAA'], [[0, 0, 1], 'AAAB'], [[0, 1, -1], 'AAH/'], [[1, 1, 1], 'AQEB'], - [[0, -73, 23], 'ALcX'] - ] + [[0, -73, 23], 'ALcX'], + ]; test('convert known data to string', () => { for (const check of data) { - const bytes = check[0] - const expected = check[1] - const actual = fromByteArray(bytes) - expect(actual).toEqual(expected) + const bytes = check[0]; + const expected = check[1]; + const actual = fromByteArray(bytes); + expect(actual).toEqual(expected); } - }) + }); function map(arr: string, callback: (char: string) => number): number[] { - const res = [] - let kValue, mappedValue + const res = []; + let kValue, mappedValue; for (let k = 0, len = arr.length; k < len; k++) { - if ((typeof arr === 'string' && !!arr.charAt(k))) { - kValue = arr.charAt(k) - mappedValue = callback(kValue) - res[k] = mappedValue + if (typeof arr === 'string' && !!arr.charAt(k)) { + kValue = arr.charAt(k); + mappedValue = callback(kValue); + res[k] = mappedValue; } else if (typeof arr !== 'string' && k in arr) { - kValue = arr[k] - mappedValue = callback(kValue) - res[k] = mappedValue + kValue = arr[k]; + mappedValue = callback(kValue); + res[k] = mappedValue; } } - return res + return res; } }); diff --git a/test/wrapper.test.ts b/test/wrapper.test.ts index 0adba436e..0429a80bf 100644 --- a/test/wrapper.test.ts +++ b/test/wrapper.test.ts @@ -212,10 +212,13 @@ describe('Tests Native Wrapper', () => { await NATIVE.sendEnvelope(env); expect(RNSentry.captureEnvelope).toBeCalledWith( - fromByteArray(utf8ToBytes('{"event_id":"event0","sent_at":"123"}\n' - + '{"type":"event","content_type":"application/json","length":87}\n' - + '{"event_id":"event0","message":"test","sdk":{"name":"test-sdk-name","version":"2.1.3"}}\n' - )), + fromByteArray( + utf8ToBytes( + '{"event_id":"event0","sent_at":"123"}\n' + + '{"type":"event","content_type":"application/json","length":87}\n' + + '{"event_id":"event0","message":"test","sdk":{"name":"test-sdk-name","version":"2.1.3"}}\n', + ), + ), { store: false }, ); }); @@ -241,10 +244,13 @@ describe('Tests Native Wrapper', () => { await NATIVE.sendEnvelope(env); expect(RNSentry.captureEnvelope).toBeCalledWith( - fromByteArray(utf8ToBytes('{"event_id":"event0","sent_at":"123"}\n' - + '{"type":"event","content_type":"application/json","length":93}\n' - + '{"event_id":"event0","sdk":{"name":"test-sdk-name","version":"2.1.3"},"instance":{"value":0}}\n' - )), + fromByteArray( + utf8ToBytes( + '{"event_id":"event0","sent_at":"123"}\n' + + '{"type":"event","content_type":"application/json","length":93}\n' + + '{"event_id":"event0","sdk":{"name":"test-sdk-name","version":"2.1.3"},"instance":{"value":0}}\n', + ), + ), { store: false }, ); }); @@ -275,10 +281,13 @@ describe('Tests Native Wrapper', () => { await NATIVE.sendEnvelope(env); expect(RNSentry.captureEnvelope).toBeCalledWith( - fromByteArray(utf8ToBytes('{"event_id":"event0","sent_at":"123"}\n' - + '{"type":"event","content_type":"application/json","length":50}\n' - + '{"event_id":"event0","message":{"message":"test"}}\n' - )), + fromByteArray( + utf8ToBytes( + '{"event_id":"event0","sent_at":"123"}\n' + + '{"type":"event","content_type":"application/json","length":50}\n' + + '{"event_id":"event0","message":{"message":"test"}}\n', + ), + ), { store: false }, ); }); @@ -311,10 +320,13 @@ describe('Tests Native Wrapper', () => { await NATIVE.sendEnvelope(env); expect(RNSentry.captureEnvelope).toBeCalledWith( - fromByteArray(utf8ToBytes('{"event_id":"event0","sent_at":"123"}\n' - + '{"type":"event","content_type":"application/json","length":104}\n' - + '{"event_id":"event0","exception":{"values":[{"mechanism":{"handled":true,"type":""}}]},"breadcrumbs":[]}\n' - )), + fromByteArray( + utf8ToBytes( + '{"event_id":"event0","sent_at":"123"}\n' + + '{"type":"event","content_type":"application/json","length":104}\n' + + '{"event_id":"event0","exception":{"values":[{"mechanism":{"handled":true,"type":""}}]},"breadcrumbs":[]}\n', + ), + ), { store: false }, ); }); @@ -337,10 +349,13 @@ describe('Tests Native Wrapper', () => { await NATIVE.sendEnvelope(env); expect(RNSentry.captureEnvelope).toBeCalledWith( - fromByteArray(utf8ToBytes('{"event_id":"event0","sent_at":"123"}\n' - + '{"type":"event","content_type":"application/json","length":38}\n' - + '{"event_id":"event0","breadcrumbs":[]}\n' - )), + fromByteArray( + utf8ToBytes( + '{"event_id":"event0","sent_at":"123"}\n' + + '{"type":"event","content_type":"application/json","length":38}\n' + + '{"event_id":"event0","breadcrumbs":[]}\n', + ), + ), { store: false }, ); }); @@ -373,10 +388,13 @@ describe('Tests Native Wrapper', () => { await NATIVE.sendEnvelope(env); expect(RNSentry.captureEnvelope).toBeCalledWith( - fromByteArray(utf8ToBytes('{"event_id":"event0","sent_at":"123"}\n' - + '{"type":"event","content_type":"application/json","length":125}\n' - + '{"event_id":"event0","exception":{"values":[{"mechanism":{"handled":false,"type":""}}]},"breadcrumbs":[{"message":"crumb!"}]}\n' - )), + fromByteArray( + utf8ToBytes( + '{"event_id":"event0","sent_at":"123"}\n' + + '{"type":"event","content_type":"application/json","length":125}\n' + + '{"event_id":"event0","exception":{"values":[{"mechanism":{"handled":false,"type":""}}]},"breadcrumbs":[{"message":"crumb!"}]}\n', + ), + ), { store: true }, ); }); From 3e4b1f232ee17d0e12377c892ee2d94009c60f3d Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 27 Nov 2023 20:12:28 +0100 Subject: [PATCH 10/15] fix tests bad merge --- test/wrapper.test.ts | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/test/wrapper.test.ts b/test/wrapper.test.ts index 6b570d965..ecc695c06 100644 --- a/test/wrapper.test.ts +++ b/test/wrapper.test.ts @@ -377,10 +377,12 @@ describe('Tests Native Wrapper', () => { await NATIVE.sendEnvelope(env); expect(RNSentry.captureEnvelope).toBeCalledWith( - utf8ToBytes( - '{"event_id":"event0","sent_at":"123"}\n' + - '{"type":"event","content_type":"application/json","length":104}\n' + - '{"event_id":"event0","exception":{"values":[{"mechanism":{"handled":true,"type":""}}]},"breadcrumbs":[]}\n', + fromByteArray( + utf8ToBytes( + '{"event_id":"event0","sent_at":"123"}\n' + + '{"type":"event","content_type":"application/json","length":124}\n' + + '{"event_id":"event0","exception":{"values":[{"mechanism":{"handled":true,"type":""}}]},"breadcrumbs":[{"message":"crumb!"}]}\n', + ), ), { store: false }, ); @@ -404,10 +406,12 @@ describe('Tests Native Wrapper', () => { await NATIVE.sendEnvelope(env); expect(RNSentry.captureEnvelope).toBeCalledWith( - utf8ToBytes( - '{"event_id":"event0","sent_at":"123"}\n' + - '{"type":"event","content_type":"application/json","length":38}\n' + - '{"event_id":"event0","breadcrumbs":[]}\n', + fromByteArray( + utf8ToBytes( + '{"event_id":"event0","sent_at":"123"}\n' + + '{"type":"event","content_type":"application/json","length":58}\n' + + '{"event_id":"event0","breadcrumbs":[{"message":"crumb!"}]}\n', + ), ), { store: false }, ); From d4381388eb144c805979ea2e2cd3a8ce9cedc94d Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 27 Nov 2023 20:14:11 +0100 Subject: [PATCH 11/15] fix changelog --- CHANGELOG.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1247442f..9989842b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## Unreleased + +### Fixes + +- Encode envelopes using Base64, fix array length limit when transferring over Bridge. ([#2852](https://github.com/getsentry/sentry-react-native/pull/2852)) + - This fix requires a rebuild of the native app + ## 5.14.1 ### Fixes @@ -382,11 +389,6 @@ This has been fixed in [version `5.9.1`](https://github.com/getsentry/sentry-rea ## 5.5.0 -### Fixes - -- Encode envelopes using Base64, fix array length limit when transferring over Bridge. ([#2852](https://github.com/getsentry/sentry-react-native/pull/2852)) - - This fix requires a rebuild of the native app - ### Features - Add `expo`, `react_native_version` and `hermes_version` to React Native Context ([#3050](https://github.com/getsentry/sentry-react-native/pull/3050)) From f1da7fb2d1ff6bb78dc8310817760ca21080ef44 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 27 Nov 2023 20:23:53 +0100 Subject: [PATCH 12/15] fix license --- src/js/vendor/base64-js/fromByteArray.ts | 5 ++--- test/vendor/base64-js/big-data.test.ts | 4 ++-- test/vendor/base64-js/convert.test.ts | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/js/vendor/base64-js/fromByteArray.ts b/src/js/vendor/base64-js/fromByteArray.ts index 01a02d655..aa64a2b02 100644 --- a/src/js/vendor/base64-js/fromByteArray.ts +++ b/src/js/vendor/base64-js/fromByteArray.ts @@ -1,7 +1,4 @@ /* eslint-disable */ - -// Adapted from https://github.dev/beatgammit/base64-js/blob/88957c9943c7e2a0f03cdf73e71d579e433627d3/index.js#L119 - // The MIT License (MIT) // Copyright (c) 2014 Jameson Little @@ -24,6 +21,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +// Adapted from https://github.dev/beatgammit/base64-js/blob/88957c9943c7e2a0f03cdf73e71d579e433627d3/index.js#L119 + const lookup: string[] = []; const code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; diff --git a/test/vendor/base64-js/big-data.test.ts b/test/vendor/base64-js/big-data.test.ts index 3b9ec5a7a..b46898113 100644 --- a/test/vendor/base64-js/big-data.test.ts +++ b/test/vendor/base64-js/big-data.test.ts @@ -1,5 +1,3 @@ -// Adapted from https://github.dev/beatgammit/base64-js/blob/88957c9943c7e2a0f03cdf73e71d579e433627d3/test/big-data.js#L4 - // The MIT License (MIT) // Copyright (c) 2014 Jameson Little @@ -22,6 +20,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +// Adapted from https://github.dev/beatgammit/base64-js/blob/88957c9943c7e2a0f03cdf73e71d579e433627d3/test/big-data.js#L4 + import { fromByteArray } from '../../../src/js/vendor'; describe('base64-js', () => { diff --git a/test/vendor/base64-js/convert.test.ts b/test/vendor/base64-js/convert.test.ts index c2e63713a..e6e78813b 100644 --- a/test/vendor/base64-js/convert.test.ts +++ b/test/vendor/base64-js/convert.test.ts @@ -1,5 +1,3 @@ -// Adapted from https://github.dev/beatgammit/base64-js/blob/88957c9943c7e2a0f03cdf73e71d579e433627d3/test/convert.js#L15 - // The MIT License (MIT) // Copyright (c) 2014 Jameson Little @@ -22,6 +20,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +// Adapted from https://github.dev/beatgammit/base64-js/blob/88957c9943c7e2a0f03cdf73e71d579e433627d3/test/convert.js#L15 + import { fromByteArray } from '../../../src/js/vendor'; describe('base64-js', () => { From da0d5966d33a3601cbf49d2078b39987723744a9 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 27 Nov 2023 20:30:19 +0100 Subject: [PATCH 13/15] fix lint --- src/js/vendor/base64-js/fromByteArray.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/js/vendor/base64-js/fromByteArray.ts b/src/js/vendor/base64-js/fromByteArray.ts index aa64a2b02..466b12532 100644 --- a/src/js/vendor/base64-js/fromByteArray.ts +++ b/src/js/vendor/base64-js/fromByteArray.ts @@ -1,4 +1,5 @@ /* eslint-disable */ + // The MIT License (MIT) // Copyright (c) 2014 Jameson Little From 0fe88c0bc180917d506963a0ed321bcc978c114f Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 27 Nov 2023 20:37:43 +0100 Subject: [PATCH 14/15] add js docs --- src/js/vendor/base64-js/fromByteArray.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/vendor/base64-js/fromByteArray.ts b/src/js/vendor/base64-js/fromByteArray.ts index 466b12532..9809d754c 100644 --- a/src/js/vendor/base64-js/fromByteArray.ts +++ b/src/js/vendor/base64-js/fromByteArray.ts @@ -47,7 +47,7 @@ function encodeChunk(uint8: Uint8Array | number[], start: number, end: number): } /** - * + * Converts a Uint8Array or Array of bytes into a string representation of base64. */ export function fromByteArray(uint8: Uint8Array | number[]): string { let tmp; From 449c39933baf8c90002dd842cffa884a331dc423 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Wed, 29 Nov 2023 16:24:16 +0100 Subject: [PATCH 15/15] fix review comments --- ios/RNSentry.mm | 4 ++-- src/js/vendor/base64-js/fromByteArray.ts | 3 +-- src/js/vendor/base64-js/index.ts | 2 +- src/js/vendor/index.ts | 2 +- src/js/wrapper.ts | 4 ++-- test/vendor/base64-js/big-data.test.ts | 4 ++-- test/vendor/base64-js/convert.test.ts | 6 +++--- test/wrapper.test.ts | 14 +++++++------- 8 files changed, 19 insertions(+), 20 deletions(-) diff --git a/ios/RNSentry.mm b/ios/RNSentry.mm index 4e78960ec..f205b01bf 100644 --- a/ios/RNSentry.mm +++ b/ios/RNSentry.mm @@ -396,12 +396,12 @@ - (NSDictionary*) fetchNativeStackFramesBy: (NSArray*)instructionsAdd }); } -RCT_EXPORT_METHOD(captureEnvelope:(NSString * _Nonnull)bytes +RCT_EXPORT_METHOD(captureEnvelope:(NSString * _Nonnull)rawBytes options: (NSDictionary * _Nonnull)options resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { - NSData *data = [[NSData alloc] initWithBase64EncodedString:bytes options:0]; + NSData *data = [[NSData alloc] initWithBase64EncodedString:rawBytes options:0]; SentryEnvelope *envelope = [PrivateSentrySDKOnly envelopeWithData:data]; if (envelope == nil) { diff --git a/src/js/vendor/base64-js/fromByteArray.ts b/src/js/vendor/base64-js/fromByteArray.ts index 9809d754c..51c046b0a 100644 --- a/src/js/vendor/base64-js/fromByteArray.ts +++ b/src/js/vendor/base64-js/fromByteArray.ts @@ -42,14 +42,13 @@ function encodeChunk(uint8: Uint8Array | number[], start: number, end: number): tmp = ((uint8[i] << 16) & 0xff0000) + ((uint8[i + 1] << 8) & 0xff00) + (uint8[i + 2] & 0xff); output.push(tripletToBase64(tmp)); } - // console.log('encodeChunk', output.length, uint8.length, start, end); return output.join(''); } /** * Converts a Uint8Array or Array of bytes into a string representation of base64. */ -export function fromByteArray(uint8: Uint8Array | number[]): string { +export function base64StringFromByteArray(uint8: Uint8Array | number[]): string { let tmp; const len = uint8.length; const extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes diff --git a/src/js/vendor/base64-js/index.ts b/src/js/vendor/base64-js/index.ts index 63a97c19b..14788724b 100644 --- a/src/js/vendor/base64-js/index.ts +++ b/src/js/vendor/base64-js/index.ts @@ -1 +1 @@ -export { fromByteArray } from './fromByteArray'; +export { base64StringFromByteArray } from './fromByteArray'; diff --git a/src/js/vendor/index.ts b/src/js/vendor/index.ts index 88713f48b..0f9ae3540 100644 --- a/src/js/vendor/index.ts +++ b/src/js/vendor/index.ts @@ -1,3 +1,3 @@ export { utf8ToBytes } from './buffer'; -export { fromByteArray } from './base64-js'; +export { base64StringFromByteArray } from './base64-js'; diff --git a/src/js/wrapper.ts b/src/js/wrapper.ts index 9778c44f7..b108a84eb 100644 --- a/src/js/wrapper.ts +++ b/src/js/wrapper.ts @@ -27,7 +27,7 @@ import type * as Hermes from './profiling/hermes'; import type { NativeProfileEvent } from './profiling/nativeTypes'; import type { RequiredKeysUser } from './user'; import { isTurboModuleEnabled } from './utils/environment'; -import { fromByteArray, utf8ToBytes } from './vendor'; +import { base64StringFromByteArray, utf8ToBytes } from './vendor'; const RNSentry: Spec | undefined = isTurboModuleEnabled() ? TurboModuleRegistry.get('RNSentry') @@ -173,7 +173,7 @@ export const NATIVE: SentryNativeWrapper = { envelopeBytes = newBytes; } - await RNSentry.captureEnvelope(fromByteArray(envelopeBytes), { store: hardCrashed }); + await RNSentry.captureEnvelope(base64StringFromByteArray(envelopeBytes), { store: hardCrashed }); }, /** diff --git a/test/vendor/base64-js/big-data.test.ts b/test/vendor/base64-js/big-data.test.ts index b46898113..750336b0d 100644 --- a/test/vendor/base64-js/big-data.test.ts +++ b/test/vendor/base64-js/big-data.test.ts @@ -22,7 +22,7 @@ // Adapted from https://github.dev/beatgammit/base64-js/blob/88957c9943c7e2a0f03cdf73e71d579e433627d3/test/big-data.js#L4 -import { fromByteArray } from '../../../src/js/vendor'; +import { base64StringFromByteArray } from '../../../src/js/vendor'; describe('base64-js', () => { test('convert big data to base64', () => { @@ -31,7 +31,7 @@ describe('base64-js', () => { for (let i = 0, length = big.length; i < length; ++i) { big[i] = i % 256; } - const b64str = fromByteArray(big); + const b64str = base64StringFromByteArray(big); const arr = Uint8Array.from(Buffer.from(b64str, 'base64')); expect(arr).toEqual(big); }); diff --git a/test/vendor/base64-js/convert.test.ts b/test/vendor/base64-js/convert.test.ts index e6e78813b..d8aa7527b 100644 --- a/test/vendor/base64-js/convert.test.ts +++ b/test/vendor/base64-js/convert.test.ts @@ -22,14 +22,14 @@ // Adapted from https://github.dev/beatgammit/base64-js/blob/88957c9943c7e2a0f03cdf73e71d579e433627d3/test/convert.js#L15 -import { fromByteArray } from '../../../src/js/vendor'; +import { base64StringFromByteArray } from '../../../src/js/vendor'; describe('base64-js', () => { const checks = ['a', 'aa', 'aaa', 'hi', 'hi!', 'hi!!', 'sup', 'sup?', 'sup?!']; test('convert to base64 and back', () => { for (const check of checks) { - const b64Str = fromByteArray( + const b64Str = base64StringFromByteArray( map(check, function (char: string) { return char.charCodeAt(0); }), @@ -53,7 +53,7 @@ describe('base64-js', () => { for (const check of data) { const bytes = check[0]; const expected = check[1]; - const actual = fromByteArray(bytes); + const actual = base64StringFromByteArray(bytes); expect(actual).toEqual(expected); } }); diff --git a/test/wrapper.test.ts b/test/wrapper.test.ts index ecc695c06..40ef52d4a 100644 --- a/test/wrapper.test.ts +++ b/test/wrapper.test.ts @@ -4,7 +4,7 @@ import * as RN from 'react-native'; import type { Spec } from '../src/js/NativeRNSentry'; import type { ReactNativeOptions } from '../src/js/options'; -import { fromByteArray, utf8ToBytes } from '../src/js/vendor'; +import { base64StringFromByteArray, utf8ToBytes } from '../src/js/vendor'; import { NATIVE } from '../src/js/wrapper'; jest.mock('react-native', () => { @@ -269,7 +269,7 @@ describe('Tests Native Wrapper', () => { await NATIVE.sendEnvelope(env); expect(RNSentry.captureEnvelope).toBeCalledWith( - fromByteArray( + base64StringFromByteArray( utf8ToBytes( '{"event_id":"event0","sent_at":"123"}\n' + '{"type":"event","content_type":"application/json","length":87}\n' + @@ -301,7 +301,7 @@ describe('Tests Native Wrapper', () => { await NATIVE.sendEnvelope(env); expect(RNSentry.captureEnvelope).toBeCalledWith( - fromByteArray( + base64StringFromByteArray( utf8ToBytes( '{"event_id":"event0","sent_at":"123"}\n' + '{"type":"event","content_type":"application/json","length":93}\n' + @@ -338,7 +338,7 @@ describe('Tests Native Wrapper', () => { await NATIVE.sendEnvelope(env); expect(RNSentry.captureEnvelope).toBeCalledWith( - fromByteArray( + base64StringFromByteArray( utf8ToBytes( '{"event_id":"event0","sent_at":"123"}\n' + '{"type":"event","content_type":"application/json","length":50}\n' + @@ -377,7 +377,7 @@ describe('Tests Native Wrapper', () => { await NATIVE.sendEnvelope(env); expect(RNSentry.captureEnvelope).toBeCalledWith( - fromByteArray( + base64StringFromByteArray( utf8ToBytes( '{"event_id":"event0","sent_at":"123"}\n' + '{"type":"event","content_type":"application/json","length":124}\n' + @@ -406,7 +406,7 @@ describe('Tests Native Wrapper', () => { await NATIVE.sendEnvelope(env); expect(RNSentry.captureEnvelope).toBeCalledWith( - fromByteArray( + base64StringFromByteArray( utf8ToBytes( '{"event_id":"event0","sent_at":"123"}\n' + '{"type":"event","content_type":"application/json","length":58}\n' + @@ -445,7 +445,7 @@ describe('Tests Native Wrapper', () => { await NATIVE.sendEnvelope(env); expect(RNSentry.captureEnvelope).toBeCalledWith( - fromByteArray( + base64StringFromByteArray( utf8ToBytes( '{"event_id":"event0","sent_at":"123"}\n' + '{"type":"event","content_type":"application/json","length":125}\n' +