Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support obfuscation for Linux apps #2431

Merged
merged 11 commits into from
Nov 22, 2024
Merged
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 .github/workflows/flutter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ jobs:
- name: 'Setup Linux'
run: |
sudo apt update
sudo apt install -y cmake dbus libblkid-dev libgtk-3-dev liblzma-dev ninja-build pkg-config xvfb
sudo apt install -y cmake dbus libblkid-dev libgtk-3-dev liblzma-dev ninja-build pkg-config xvfb libcurl4-openssl-dev
sudo apt install -y network-manager upower
if: matrix.target == 'linux'

Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Features

- Linux native error & obfuscation support ([#2431](https://github.com/getsentry/sentry-dart/pull/2431))

## 8.11.0-beta.1

### Features
Expand Down
3 changes: 2 additions & 1 deletion dart/lib/src/platform_checker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ class PlatformChecker {
return platform.isAndroid ||
platform.isIOS ||
platform.isMacOS ||
platform.isWindows;
platform.isWindows ||
platform.isLinux;
}

static bool _isWebWithWasmSupport() {
Expand Down
2 changes: 1 addition & 1 deletion flutter/example/linux/flutter/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ add_custom_command(
COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
linux-x64 ${CMAKE_BUILD_TYPE}
${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
VERBATIM
)
add_custom_target(flutter_assemble DEPENDS
Expand Down
46 changes: 36 additions & 10 deletions flutter/example/linux/my_application.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,21 @@ static void my_application_activate(GApplication* application) {
// if future cases occur).
gboolean use_header_bar = TRUE;
#ifdef GDK_WINDOWING_X11
GdkScreen *screen = gtk_window_get_screen(window);
GdkScreen* screen = gtk_window_get_screen(window);
if (GDK_IS_X11_SCREEN(screen)) {
const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
use_header_bar = FALSE;
}
const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
use_header_bar = FALSE;
}
}
#endif
if (use_header_bar) {
GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
gtk_widget_show(GTK_WIDGET(header_bar));
gtk_header_bar_set_title(header_bar, "sentry_flutter_example");
gtk_header_bar_set_show_close_button(header_bar, TRUE);
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
}
else {
} else {
gtk_window_set_title(window, "sentry_flutter_example");
}

Expand All @@ -64,7 +63,7 @@ static void my_application_activate(GApplication* application) {
}

// Implements GApplication::local_command_line.
static gboolean my_application_local_command_line(GApplication* application, gchar ***arguments, int *exit_status) {
static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) {
MyApplication* self = MY_APPLICATION(application);
// Strip out the first argument as it is the binary name.
self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
Expand All @@ -82,8 +81,26 @@ static gboolean my_application_local_command_line(GApplication* application, gch
return TRUE;
}

// Implements GApplication::startup.
static void my_application_startup(GApplication* application) {
//MyApplication* self = MY_APPLICATION(object);

// Perform any actions required at application startup.

G_APPLICATION_CLASS(my_application_parent_class)->startup(application);
}

// Implements GApplication::shutdown.
static void my_application_shutdown(GApplication* application) {
//MyApplication* self = MY_APPLICATION(object);

// Perform any actions required at application shutdown.

G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application);
}

// Implements GObject::dispose.
static void my_application_dispose(GObject *object) {
static void my_application_dispose(GObject* object) {
MyApplication* self = MY_APPLICATION(object);
g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
Expand All @@ -92,13 +109,22 @@ static void my_application_dispose(GObject *object) {
static void my_application_class_init(MyApplicationClass* klass) {
G_APPLICATION_CLASS(klass)->activate = my_application_activate;
G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
G_APPLICATION_CLASS(klass)->startup = my_application_startup;
G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown;
G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
}

static void my_application_init(MyApplication* self) {}

MyApplication* my_application_new() {
// Set the program name to the application ID, which helps various systems
// like GTK and desktop environments map this running application to its
// corresponding .desktop file. This ensures better integration by allowing
// the application to be recognized beyond its binary name.
g_set_prgname(APPLICATION_ID);

return MY_APPLICATION(g_object_new(my_application_get_type(),
"application-id", APPLICATION_ID,
"flags", G_APPLICATION_NON_UNIQUE,
nullptr));
}
3 changes: 3 additions & 0 deletions flutter/example/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ elif [ "$1" == "macos" ]; then
elif [ "$1" == "windows" ]; then
flutter build windows --split-debug-info=$symbolsDir --obfuscate
launchCmd='./build/windows/x64/runner/Release/sentry_flutter_example.exe'
elif [ "$1" == "linux" ]; then
flutter build linux --split-debug-info=$symbolsDir --obfuscate
launchCmd='./build/linux/x64/release/bundle/sentry_flutter_example'
else
if [ "$1" == "" ]; then
echo -e "[\033[92mrun\033[0m] Pass the platform you'd like to run: android, ios, web"
Expand Down
11 changes: 10 additions & 1 deletion flutter/lib/src/native/c/sentry_native.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:ffi';
import 'dart:io';
import 'dart:typed_data';

import 'package:ffi/ffi.dart';
Expand All @@ -19,7 +20,15 @@ class SentryNative with SentryNativeSafeInvoker implements SentryNativeBinding {
final SentryFlutterOptions options;

@visibleForTesting
static final native = binding.SentryNative(DynamicLibrary.open('sentry.dll'));
static final native = binding.SentryNative(DynamicLibrary.open(
'$dynamicLibraryDirectory${Platform.isWindows ? 'sentry.dll' : 'libsentry.so'}'));

/// If the path is just the library name, the loader will look for it in
/// the usual places for shared libraries:
/// - on Linux in /lib and /usr/lib
/// - on Windows in the working directory and System32
@visibleForTesting
static String dynamicLibraryDirectory = '';

@visibleForTesting
static String? crashpadPath;
Expand Down
2 changes: 1 addition & 1 deletion flutter/lib/src/native/factory_real.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ SentryNativeBinding createBinding(SentryFlutterOptions options) {
return SentryNativeCocoa(options);
} else if (platform.isAndroid) {
return SentryNativeJava(options);
} else if (platform.isWindows) {
} else if (platform.isWindows || platform.isLinux) {
return SentryNative(options);
} else {
return SentryNativeChannel(options);
Expand Down
29 changes: 7 additions & 22 deletions flutter/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,25 +1,10 @@
# The Flutter tooling requires that developers have CMake 3.10 or later
# installed. You should not increase this version, as doing so will cause
# the plugin to fail to compile for some customers of the plugin.
cmake_minimum_required(VERSION 3.10)
set(PROJECT_NAME "sentry_flutter")
project(${PROJECT_NAME} LANGUAGES CXX)

# This value is used when generating builds using this plugin, so it must
# not be changed
set(PLUGIN_NAME "sentry_flutter_plugin")
include("${CMAKE_CURRENT_SOURCE_DIR}/../sentry-native/sentry-native.cmake")

add_library(${PLUGIN_NAME} SHARED
"sentry_flutter_plugin.cc"
)
apply_standard_settings(${PLUGIN_NAME})
set_target_properties(${PLUGIN_NAME} PROPERTIES
CXX_VISIBILITY_PRESET hidden)
target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL)
target_include_directories(${PLUGIN_NAME} INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/include")
target_link_libraries(${PLUGIN_NAME} PRIVATE flutter)
target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK)

# List of absolute paths to libraries that should be bundled with the plugin
set(sentry_flutter_bundled_libraries
""
PARENT_SCOPE
)
# Even though sentry_flutter doesn't actually provide a useful plugin, we need to accommodate the Flutter tooling.
# sentry_flutter/sentry_flutter_plugin.h is included by the flutter-tool generated plugin registrar:
target_include_directories(sentry INTERFACE ${CMAKE_CURRENT_LIST_DIR})
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#ifndef FLUTTER_PLUGIN_SENTRY_FLUTTER_PLUGIN_H_
#define FLUTTER_PLUGIN_SENTRY_FLUTTER_PLUGIN_H_
#pragma once

#include <flutter_linux/flutter_linux.h>

Expand All @@ -16,11 +15,7 @@ typedef struct {
GObjectClass parent_class;
} SentryFlutterPluginClass;

FLUTTER_PLUGIN_EXPORT GType sentry_flutter_plugin_get_type();

FLUTTER_PLUGIN_EXPORT void sentry_flutter_plugin_register_with_registrar(
FlPluginRegistrar* registrar);
FlPluginRegistrar* registrar) {}

G_END_DECLS

#endif // FLUTTER_PLUGIN_SENTRY_FLUTTER_PLUGIN_H_
60 changes: 0 additions & 60 deletions flutter/linux/sentry_flutter_plugin.cc

This file was deleted.

4 changes: 2 additions & 2 deletions flutter/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ flutter:
web:
pluginClass: SentryFlutterWeb
fileName: sentry_flutter_web.dart
# Note, we cannot use `ffiPlugin: true` on Linux and windows because flutter won't add `target_link_libraries()`
# so sentry-native won't even build during the build process (since it doesn't need to).
linux:
pluginClass: SentryFlutterPlugin
windows:
# Note, we cannot use `ffiPlugin: true` because flutter tooling won't add `target_link_libraries()`
# so sentry-native won't even build during the build process (since it doesn't need to).
pluginClass: SentryFlutterPlugin
18 changes: 11 additions & 7 deletions flutter/sentry-native/sentry-native.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@ FetchContent_Declare(
FetchContent_MakeAvailable(sentry-native)

# List of absolute paths to libraries that should be bundled with the plugin.
# This list could contain prebuilt libraries, or libraries created by an
# external build triggered from this build file.
set(sentry_flutter_bundled_libraries
$<TARGET_FILE:crashpad_handler>
$<TARGET_FILE:crashpad_wer>
PARENT_SCOPE
)
# This list could contain prebuilt libraries, or libraries created by an external build triggered from this build file.
if(WIN32)
set(sentry_flutter_bundled_libraries
$<TARGET_FILE:crashpad_handler>
$<TARGET_FILE:crashpad_wer>
PARENT_SCOPE)
else()
set(sentry_flutter_bundled_libraries
$<TARGET_FILE:crashpad_handler>
PARENT_SCOPE)
endif()

# `*_plugin` is the name of the plugin library as expected by flutter.
# We don't actually need a plugin here, we just need to get the native library linked
Expand Down
8 changes: 5 additions & 3 deletions flutter/test/sentry_flutter_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,9 @@ void main() {
Transport transport = MockTransport();
final sentryFlutterOptions =
defaultTestOptions(getPlatformChecker(platform: MockPlatform.linux()))
..methodChannel = native.channel;
..methodChannel = native.channel
// We need to disable native init because libsentry.so is not available here.
..autoInitializeNativeSdk = false;

await SentryFlutter.init(
(options) async {
Expand All @@ -299,7 +301,7 @@ void main() {
);

testScopeObserver(
options: sentryFlutterOptions, expectedHasNativeScopeObserver: false);
options: sentryFlutterOptions, expectedHasNativeScopeObserver: true);

testConfiguration(
integrations: integrations,
Expand All @@ -320,7 +322,7 @@ void main() {
beforeIntegration: WidgetsFlutterBindingIntegration,
afterIntegration: OnErrorIntegration);

expect(SentryFlutter.native, isNull);
expect(SentryFlutter.native, isNotNull);
expect(Sentry.currentHub.profilerFactory, isNull);

await Sentry.close();
Expand Down
2 changes: 1 addition & 1 deletion flutter/test/sentry_native/sentry_native_test.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// We must conditionally import the actual test code, otherwise tests fail on
// a browser. @TestOn('vm') doesn't help by itself in this case because imports
// are still evaluated, thus causing a compilation failure.
@TestOn('vm && windows')
@TestOn('vm && (windows || linux)')
library sentry_native_test;

import 'package:flutter_test/flutter_test.dart';
Expand Down
Loading
Loading