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

Octernship Assignment Submission #16

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
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
94 changes: 33 additions & 61 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,77 +1,49 @@
# Information
# Flutter Rust App with Privilege Elevation

![rustdesk-banner](https://user-images.githubusercontent.com/71636191/236513788-89da3f2a-6898-4e30-a12f-b5af129858c3.png)
This application incorporates Rust code for executing privileged operations using `sudo` or `polkit` (if available). This combination of Flutter and Rust allows for a powerful and secure application with elevated privileges when necessary.

### Company information
## Prerequisites

Virtual / remote desktop infrastructure for everyone! Open source TeamViewer / Citrix alternative.
Make sure you have the following installed before proceeding:

### Why participate in an Octernship with RustDesk
- Flutter SDK: [Installation Guide](https://flutter.dev/docs/get-started/install)
- Rust Toolchain (comes with the compiler): [Installation Guide](https://www.rustup.rs)
- C/C++ Compiler (for building Rust FFI): Ensure you have a compatible C/C++ compiler for your platform.
- [flutter-rust-bridge flutter package](https://pub.dev/packages/flutter_rust_bridge)

We use Rust + Flutter and cover all platforms. [RustDesk](https://github.com/rustdesk/rustdesk) is a 40K+ GitHub Stars project. You can learn Rust and Flutter very well here.
## Getting Started

### Octernship role description
To run the Flutter Rust app with privilege elevation, follow these steps:

| Octernship info | Timelines and Stipend |
| ------------- | ------------- |
| Assignment Deadline | 20 June 2023 |
| Octernship Duration | 3 Months |
| Monthly Stipend | $500 USD |
1. Clone the repository:

### Recommended qualifications
2. Navigate to the project directory:

- Experience with Git & GitHub
- Experience with networking and basic Linux commands
- Passion to learn Rust and Flutter
- Passion for open source
- Fast learner
3. Run the Just command code:

### Eligibility
```bash
just gen
```

To participate, you must be:
4. Build and run the Flutter app:

* A [verified student](https://education.github.com/discount_requests/pack_application) on Global Campus
```bash
flutter run
```

* 18 years or older
## Screenshots
| ![Welcome Screen](assets/home_ss.png) |
|:--:|
| *The welcome screen the user is greeted with when opening the application* |

* Active contributor on GitHub (monthly)
| !['Show my root folder' Button](assets/get_root.png) |
|:--:|
| *This button prompts the user to enter their password. It elevates privilege with the sudo command* |

# Assignment
| ![Password Input Dialog](assets/sudo.png) |
|:--:|
| *The dialog that allows the user input their password* |

## Elevate priviledge to run a Linux command with Rust

The starter code is included in this repository. ‼️

### Setting up 🖥️

* Prepare your Linux environment
* Follow https://github.com/Desdaemon/flutter_rust_bridge_template/blob/main/README.md to get started
* `flutter run -d linux`
![image](https://user-images.githubusercontent.com/71636191/231404421-a203e923-0c51-42fd-9ee7-cea0ea44fdd9.png)

### Task instructions

Your task is to

- Elevate priviledge to run `ls -la /root/` with Rust, and print the result on the Flutter window

### Task Expectations

- Polkit is usually used by priviledge elevation on Linux
- Polkit may be disabled or uninstalled on some system, you need to detect if polkit works well, and elevate priviledge with alternative way

### Task submission

Students are expected to use the [GitHub Flow](https://docs.github.com/en/get-started/quickstart/github-flow) when working on their project.

1. Creating a new branch
2. Making changes on the new branch
3. Creating a Pull Request to merge changes into main branch on or before the assignment deadline.
3. Using GitHub Discussions to ask any relevant questions regarding the project

### Resources

* https://github.com/rustdesk/rustdesk/issues/2756

## Questions
We love to answer questions! We highly recommend learning by doing and looking up the questions before reaching out. If you were unable to find your solution on ChatGPT / Google / Stack Overflow, please open a new discussion in this repository.
| ![Output](assets/result.png) |
|:--:|
| *The results displayed on the screen* |
Binary file added assets/get_root.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/home_ss.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/result.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/sudo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 16 additions & 5 deletions ios/Runner/bridge_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ typedef int64_t DartPort;

typedef bool (*DartPostCObjectFnType)(DartPort port_id, void *message);

typedef struct wire_uint_8_list {
uint8_t *ptr;
int32_t len;
} wire_uint_8_list;

typedef struct DartCObject *WireSyncReturn;

void store_dart_post_cobject(DartPostCObjectFnType ptr);
Expand All @@ -21,20 +26,26 @@ uintptr_t new_dart_opaque(Dart_Handle handle);

intptr_t init_frb_dart_api_dl(void *obj);

void wire_platform(int64_t port_);
void wire_get_username(int64_t port_);

void wire_print_root_folder(int64_t port_, struct wire_uint_8_list *password);

void wire_check_polkit(int64_t port_);

void wire_rust_release_mode(int64_t port_);
struct wire_uint_8_list *new_uint_8_list_0(int32_t len);

void free_WireSyncReturn(WireSyncReturn ptr);

static int64_t dummy_method_to_enforce_bundling(void) {
int64_t dummy_var = 0;
dummy_var ^= ((int64_t) (void*) wire_platform);
dummy_var ^= ((int64_t) (void*) wire_rust_release_mode);
dummy_var ^= ((int64_t) (void*) wire_get_username);
dummy_var ^= ((int64_t) (void*) wire_print_root_folder);
dummy_var ^= ((int64_t) (void*) wire_check_polkit);
dummy_var ^= ((int64_t) (void*) new_uint_8_list_0);
dummy_var ^= ((int64_t) (void*) free_WireSyncReturn);
dummy_var ^= ((int64_t) (void*) store_dart_post_cobject);
dummy_var ^= ((int64_t) (void*) get_dart_object);
dummy_var ^= ((int64_t) (void*) drop_dart_object);
dummy_var ^= ((int64_t) (void*) new_dart_opaque);
return dummy_var;
}
}
51 changes: 35 additions & 16 deletions lib/bridge_definitions.dart
Original file line number Diff line number Diff line change
@@ -1,31 +1,50 @@
// AUTO GENERATED FILE, DO NOT EDIT.
// Generated by `flutter_rust_bridge`@ 1.62.1.
// ignore_for_file: non_constant_identifier_names, unused_element, duplicate_ignore, directives_ordering, curly_braces_in_flow_control_structures, unnecessary_lambdas, slash_for_doc_comments, prefer_const_literals_to_create_immutables, implicit_dynamic_list_literal, duplicate_import, unused_import, unnecessary_import, prefer_single_quotes, prefer_const_constructors, use_super_parameters, always_use_package_imports, annotate_overrides, invalid_use_of_protected_member, constant_identifier_names, invalid_use_of_internal_member
// Generated by `flutter_rust_bridge`@ 1.77.1.
// ignore_for_file: non_constant_identifier_names, unused_element, duplicate_ignore, directives_ordering, curly_braces_in_flow_control_structures, unnecessary_lambdas, slash_for_doc_comments, prefer_const_literals_to_create_immutables, implicit_dynamic_list_literal, duplicate_import, unused_import, unnecessary_import, prefer_single_quotes, prefer_const_constructors, use_super_parameters, always_use_package_imports, annotate_overrides, invalid_use_of_protected_member, constant_identifier_names, invalid_use_of_internal_member, prefer_is_empty, unnecessary_const

import 'bridge_generated.io.dart'
if (dart.library.html) 'bridge_generated.web.dart';
import 'dart:convert';
import 'dart:async';
import 'package:meta/meta.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge.dart';
import 'package:uuid/uuid.dart';

abstract class Native {
Future<Platform> platform({dynamic hint});
/// Rust function that retrieves the username of the current user by executing a terminal command.
/// It utilizes the underlying operating system's capabilities to obtain the username.
/// Returns a string value.
///
/// ### Example
/// ```rust
/// fn main() {
/// let username = get_username(); // returns current user's username
/// println!("Hello, {}!", username);
/// }
/// ```
Future<String> getUsername({dynamic hint});

FlutterRustBridgeTaskConstMeta get kPlatformConstMeta;
FlutterRustBridgeTaskConstMeta get kGetUsernameConstMeta;

Future<bool> rustReleaseMode({dynamic hint});
/// Rust function that uses the sudo command to elevate privilege.
/// Takes in a password as a String argument to grant access to the root folder.
///
/// ### Return Values
/// - Returns Some(String) if the function was successfullt executed and the proper rights have been granted.
/// - Returns None if the function fails to execute correctly and the proper rights have not been given to the administrator.
///
/// ### Example
/// ```rust
/// fn main() {
/// let return_statement = print_root_folder("pass1234".to_string());
/// println("{:?}", return_statement); // prints the output statement provided the password is correct or throws an error.
/// }
/// ```
Future<String?> printRootFolder({required String password, dynamic hint});

FlutterRustBridgeTaskConstMeta get kRustReleaseModeConstMeta;
}
FlutterRustBridgeTaskConstMeta get kPrintRootFolderConstMeta;

Future<String?> checkPolkit({dynamic hint});

enum Platform {
Unknown,
Android,
Ios,
Windows,
Unix,
MacIntel,
MacApple,
Wasm,
FlutterRustBridgeTaskConstMeta get kCheckPolkitConstMeta;
}
65 changes: 46 additions & 19 deletions lib/bridge_generated.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// AUTO GENERATED FILE, DO NOT EDIT.
// Generated by `flutter_rust_bridge`@ 1.62.1.
// ignore_for_file: non_constant_identifier_names, unused_element, duplicate_ignore, directives_ordering, curly_braces_in_flow_control_structures, unnecessary_lambdas, slash_for_doc_comments, prefer_const_literals_to_create_immutables, implicit_dynamic_list_literal, duplicate_import, unused_import, unnecessary_import, prefer_single_quotes, prefer_const_constructors, use_super_parameters, always_use_package_imports, annotate_overrides, invalid_use_of_protected_member, constant_identifier_names, invalid_use_of_internal_member
// Generated by `flutter_rust_bridge`@ 1.77.1.
// ignore_for_file: non_constant_identifier_names, unused_element, duplicate_ignore, directives_ordering, curly_braces_in_flow_control_structures, unnecessary_lambdas, slash_for_doc_comments, prefer_const_literals_to_create_immutables, implicit_dynamic_list_literal, duplicate_import, unused_import, unnecessary_import, prefer_single_quotes, prefer_const_constructors, use_super_parameters, always_use_package_imports, annotate_overrides, invalid_use_of_protected_member, constant_identifier_names, invalid_use_of_internal_member, prefer_is_empty, unnecessary_const

import "bridge_definitions.dart";
import 'dart:convert';
import 'dart:async';
import 'package:meta/meta.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge.dart';
import 'package:uuid/uuid.dart';
import 'bridge_generated.io.dart'
if (dart.library.html) 'bridge_generated.web.dart';

Expand All @@ -19,35 +20,52 @@ class NativeImpl implements Native {
factory NativeImpl.wasm(FutureOr<WasmModule> module) =>
NativeImpl(module as ExternalLibrary);
NativeImpl.raw(this._platform);
Future<Platform> platform({dynamic hint}) {
Future<String> getUsername({dynamic hint}) {
return _platform.executeNormal(FlutterRustBridgeTask(
callFfi: (port_) => _platform.inner.wire_platform(port_),
parseSuccessData: _wire2api_platform,
constMeta: kPlatformConstMeta,
callFfi: (port_) => _platform.inner.wire_get_username(port_),
parseSuccessData: _wire2api_String,
constMeta: kGetUsernameConstMeta,
argValues: [],
hint: hint,
));
}

FlutterRustBridgeTaskConstMeta get kPlatformConstMeta =>
FlutterRustBridgeTaskConstMeta get kGetUsernameConstMeta =>
const FlutterRustBridgeTaskConstMeta(
debugName: "platform",
debugName: "get_username",
argNames: [],
);

Future<bool> rustReleaseMode({dynamic hint}) {
Future<String?> printRootFolder({required String password, dynamic hint}) {
var arg0 = _platform.api2wire_String(password);
return _platform.executeNormal(FlutterRustBridgeTask(
callFfi: (port_) => _platform.inner.wire_rust_release_mode(port_),
parseSuccessData: _wire2api_bool,
constMeta: kRustReleaseModeConstMeta,
callFfi: (port_) => _platform.inner.wire_print_root_folder(port_, arg0),
parseSuccessData: _wire2api_opt_String,
constMeta: kPrintRootFolderConstMeta,
argValues: [password],
hint: hint,
));
}

FlutterRustBridgeTaskConstMeta get kPrintRootFolderConstMeta =>
const FlutterRustBridgeTaskConstMeta(
debugName: "print_root_folder",
argNames: ["password"],
);

Future<String?> checkPolkit({dynamic hint}) {
return _platform.executeNormal(FlutterRustBridgeTask(
callFfi: (port_) => _platform.inner.wire_check_polkit(port_),
parseSuccessData: _wire2api_opt_String,
constMeta: kCheckPolkitConstMeta,
argValues: [],
hint: hint,
));
}

FlutterRustBridgeTaskConstMeta get kRustReleaseModeConstMeta =>
FlutterRustBridgeTaskConstMeta get kCheckPolkitConstMeta =>
const FlutterRustBridgeTaskConstMeta(
debugName: "rust_release_mode",
debugName: "check_polkit",
argNames: [],
);

Expand All @@ -56,19 +74,28 @@ class NativeImpl implements Native {
}
// Section: wire2api

bool _wire2api_bool(dynamic raw) {
return raw as bool;
String _wire2api_String(dynamic raw) {
return raw as String;
}

String? _wire2api_opt_String(dynamic raw) {
return raw == null ? null : _wire2api_String(raw);
}

int _wire2api_i32(dynamic raw) {
int _wire2api_u8(dynamic raw) {
return raw as int;
}

Platform _wire2api_platform(dynamic raw) {
return Platform.values[raw];
Uint8List _wire2api_uint_8_list(dynamic raw) {
return raw as Uint8List;
}
}

// Section: api2wire

@protected
int api2wire_u8(int raw) {
return raw;
}

// Section: finalizer
Loading