Skip to content

Commit

Permalink
fix: fix #2 and add runtime feature checks
Browse files Browse the repository at this point in the history
  • Loading branch information
Dan0xE committed Apr 26, 2024
1 parent 23e1f88 commit 37264fd
Show file tree
Hide file tree
Showing 17 changed files with 220 additions and 59 deletions.
9 changes: 7 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "protectus"
version = "0.1.1"
version = "0.1.2"
edition = "2021"
authors = ["Dan0xE <[email protected]>"]
exclude = ["/webview-src", "/examples"]
Expand All @@ -16,4 +16,9 @@ base64 = "0.22"
chrono = "0.4"

[build-dependencies]
tauri-plugin = { version = "2.0.0-beta", features = ["build"] }
tauri-plugin = { version = "2.0.0-beta", features = ["build"] }

[features]
default = ["service"]
service = []
licensing = []
38 changes: 23 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
# Protectus

> [!WARNING]
> Currently only works with VmProtect Ultimate, see [#2](https://github.com/Dan0xE/protectus/issues/2)
Call VmProtect functions directly from your Tauri WebView.

---

## Supported functions

Expand All @@ -23,8 +17,24 @@ This will be expanded in the near future!

## Tauri Plugin Permissions

> [!IMPORTANT]
> Protectus performs feature checks at runtime before executing any function.
> This is done to verify whether a feature that the called function depends on (for example, 'licensing')
> is enabled in the Rust backend, in order to prevent unwanted behavior.
> Without adding the following permission, Protectus will not function properly!
```json
"permissions": [
"protectus:allow-feature-check-command"
]
```

Protectus Permission List:


```json
"permissions": [
"protectus:allow-feature-check-command"
"protectus:allow-is-debugger-present-command",
"protectus:allow-is-protected-command",
"protectus:allow-is-virtual-machine-command",
Expand All @@ -42,17 +52,15 @@ This will be expanded in the near future!
- VmProtect Installation
- Tauri Version >= 2.0.0-beta

When using a Debug Build of your Application, please copy the following files from VmProtect into your target/debug folder:
When using a Debug Build of your application, copy either all files or only the files necessary for your operating system and architecture from VmProtect into your `target/debug` folder:

- libVMProtectSDK.dylib
- libVMProtectSDK32.so
- libVMProtectSDK64.so
- VMProtectSDK32.dll
- VMProtectSDK32.lib
- VMProtectSDK64.dll
- VMProtectSDK64.lib
- For macOS: `libVMProtectSDK.dylib`
- For 32-bit Linux: `libVMProtectSDK32.so`
- For 64-bit Linux: `libVMProtectSDK64.so`
- For 32-bit Windows: `VMProtectSDK32.dll`, `VMProtectSDK32.lib`
- For 64-bit Windows: `VMProtectSDK64.dll`, `VMProtectSDK64.lib`

## Limitations of the Demo
## Limitations when using Debug Builds

Some functions do not return a valid result until the Application is protected with VmProtect

Expand Down
3 changes: 2 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub fn main() {
"deactivate_license_command",
"is_protected_command",
"is_virtual_machine_command",
"is_debugger_present_command"
"is_debugger_present_command",
"feature_check_command"
]).build();
}
2 changes: 1 addition & 1 deletion examples/svelte-app/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ tauri = { version = "2.0.0-beta", features = [] }
tauri-plugin-shell = "2.0.0-beta"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
protectus = { path = "../../../"}
protectus = { path = "../../../", features = ["licensing"] }
tauri-plugin-dialog = "2.0.0-beta.4"

3 changes: 2 additions & 1 deletion examples/svelte-app/src-tauri/capabilities/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"protectus:allow-get-serial-number-state-command",
"protectus:allow-activate-license-command",
"protectus:allow-deactivate-license-command",
"protectus:allow-set-serial-number-command"
"protectus:allow-set-serial-number-command",
"protectus:allow-feature-check-command"
]
}
2 changes: 1 addition & 1 deletion examples/svelte-app/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"productName": "svelte-app",
"version": "0.0.0",
"identifier": "com.tauri.dev",
"identifier": "com.protectus.dev",
"build": {
"beforeDevCommand": "pnpm dev",
"devUrl": "http://localhost:1420",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "protectus",
"version": "0.1.1",
"version": "0.1.2",
"main": "webview-dist/index.js",
"license": "MIT",
"dependencies": {
Expand Down
13 changes: 13 additions & 0 deletions permissions/autogenerated/commands/feature_check_command.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Automatically generated - DO NOT EDIT!

"$schema" = "../../schemas/schema.json"

[[permission]]
identifier = "allow-feature-check-command"
description = "Enables the feature_check_command command without any pre-configured scope."
commands.allow = ["feature_check_command"]

[[permission]]
identifier = "deny-feature-check-command"
description = "Denies the feature_check_command command without any pre-configured scope."
commands.deny = ["feature_check_command"]
2 changes: 2 additions & 0 deletions permissions/autogenerated/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
|`deny-activate-license-command`|Denies the activate_license_command command without any pre-configured scope.|
|`allow-deactivate-license-command`|Enables the deactivate_license_command command without any pre-configured scope.|
|`deny-deactivate-license-command`|Denies the deactivate_license_command command without any pre-configured scope.|
|`allow-feature-check-command`|Enables the feature_check_command command without any pre-configured scope.|
|`deny-feature-check-command`|Denies the feature_check_command command without any pre-configured scope.|
|`allow-get-hwid-command`|Enables the get_hwid_command command without any pre-configured scope.|
|`deny-get-hwid-command`|Denies the get_hwid_command command without any pre-configured scope.|
|`allow-get-serial-number-data-command`|Enables the get_serial_number_data_command command without any pre-configured scope.|
Expand Down
14 changes: 14 additions & 0 deletions permissions/schemas/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,20 @@
"deny-deactivate-license-command"
]
},
{
"description": "allow-feature-check-command -> Enables the feature_check_command command without any pre-configured scope.",
"type": "string",
"enum": [
"allow-feature-check-command"
]
},
{
"description": "deny-feature-check-command -> Denies the feature_check_command command without any pre-configured scope.",
"type": "string",
"enum": [
"deny-feature-check-command"
]
},
{
"description": "allow-get-hwid-command -> Enables the get_hwid_command command without any pre-configured scope.",
"type": "string",
Expand Down
21 changes: 21 additions & 0 deletions src/helper.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::time::Duration;

use serde::Serialize;
use tauri::command;
use vmprotect::licensing::{ActivationStatus, SerialNumberData, SerialState};

#[derive(Serialize)]
Expand Down Expand Up @@ -68,3 +69,23 @@ pub fn activation_status_to_error_message(status: ActivationStatus) -> String {
ActivationStatus::NulError => "The license contains a NUL character.".to_string(),
}
}

#[derive(Serialize)]
pub struct Features {
pub licensing: bool,
pub service: bool,
}

impl Features {
pub fn new() -> Features {
Features {
licensing: cfg!(feature = "licensing"),
service: cfg!(feature = "service"),
}
}
}

#[command]
pub fn feature_check_command() -> Result<Features, ()> {
Ok(Features::new())
}
40 changes: 33 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,51 @@
pub mod helper;
#[cfg(feature = "licensing")]
pub mod licensing;
#[cfg(feature = "service")]
pub mod service;

use serde::Serialize;
use tauri::plugin::{Builder, TauriPlugin};
use tauri::Runtime;
use tauri::{command, Runtime};


#[cfg(feature = "licensing")]
use crate::licensing::*;
#[cfg(feature = "service")]
use crate::service::*;
use helper::feature_check_command;





pub fn init<R: Runtime>() -> TauriPlugin<R> {
Builder::new("protectus")
.invoke_handler(tauri::generate_handler![
let mut builder = Builder::new("protectus");

#[cfg(feature = "licensing")]
{
use crate::licensing::*;
builder = builder.invoke_handler(tauri::generate_handler![
feature_check_command,
get_hwid_command,
set_serial_number_command,
get_serial_number_state_command,
get_serial_number_data_command,
activate_license_command,
deactivate_license_command,
is_protected_command,
]);
}

#[cfg(feature = "service")]
{
use crate::service::*;
builder = builder.invoke_handler(tauri::generate_handler![
feature_check_command,
is_virtual_machine_command,
is_debugger_present_command
])
.build()
is_debugger_present_command,
is_protected_command
]);
}

builder.build()
}
5 changes: 3 additions & 2 deletions src/licensing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ pub fn get_hwid_command() -> Result<String, ()> {
Ok(get_hwid())
}


#[command]
pub fn set_serial_number_command(serial_str: String) -> Result<String, String> {
let serial_bytes = serial_str.into_bytes();

match set_serial_number(serial_bytes) {
Ok(serial_state) => {
let states = serialize_serial_state(serial_state);
Expand All @@ -27,7 +28,7 @@ pub fn set_serial_number_command(serial_str: String) -> Result<String, String> {
}

#[command]
pub fn get_serial_number_state_command() -> Result<String, ()> {
pub fn get_serial_number_state_command() -> Result<String, String> {
let serial_state = get_serial_number_state();
let states = serialize_serial_state(serial_state);
Ok(format!("Serial state: {}", states.join(", ")))
Expand Down
6 changes: 3 additions & 3 deletions src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ use tauri::command;
use vmprotect::service::{is_debugger_present, is_protected, is_virtual_machine};

#[command]
pub fn is_protected_command() -> Result<bool, ()> {
pub fn is_protected_command() -> Result<bool, String> {
Ok(is_protected())
}

#[command]
pub fn is_virtual_machine_command() -> Result<bool, ()> {
pub fn is_virtual_machine_command() -> Result<bool, String> {
Ok(is_virtual_machine())
}

#[command]
pub fn is_debugger_present_command(check_kernel_mode: bool) -> Result<bool, ()> {
pub fn is_debugger_present_command(check_kernel_mode: bool) -> Result<bool, String> {
Ok(is_debugger_present(check_kernel_mode))
}
34 changes: 34 additions & 0 deletions webview-src/helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {invoke} from '@tauri-apps/api/core';

interface Features {
licensing: boolean;
service: boolean;
}

type GenericFunc<F> = () => Promise<F>;

/** Checks if the required feature for the passed function is enabled on the rust backend
* @param {keyof Features} featureEnabled Feature that has to be enabled for this function to be executed
* @param {GenericFunc<F>[]} functionsToExecute Functions that should be executed if the required feature is enabled
* @throws Throws if the required feature is not enabled in the rust backend
*/
export async function featureGate<F>(
featureEnabled: keyof Features,
...functionsToExecute: GenericFunc<F>[]
): Promise<F | undefined> {
const features: Features = await invoke(
'plugin:protectus|feature_check_command'
);

if (features[featureEnabled]) {
let lastResult: F | undefined = undefined;
for (const fn of functionsToExecute) {
lastResult = await fn();
}
return lastResult;
}

throw new Error(
`${functionsToExecute} called but required feature ${featureEnabled} is not enabled!`
);
}
Loading

0 comments on commit 37264fd

Please sign in to comment.