mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-04-23 11:36:13 +02:00
chore: Merge branch v1 into v2 (#702)
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"sql": patch
|
||||
---
|
||||
|
||||
Fixed an issue where float-like values were decoded as `null`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"stronghold": patch
|
||||
---
|
||||
|
||||
Added `Builder::with_argon2`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"positioner": patch
|
||||
---
|
||||
|
||||
`TrayLeft`, `TrayRight` and `TrayCenter` will now position the window according to the tray position relative to the monitor dimensions to prevent windows being displayed partially off-screen.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"upload": patch
|
||||
---
|
||||
|
||||
Use `BufWriter` to reduce IO calls.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"websocket": patch
|
||||
"websocket-js": patch
|
||||
---
|
||||
|
||||
Add support for custom request headers.
|
||||
Generated
+799
-761
File diff suppressed because it is too large
Load Diff
+12
-5
@@ -13,18 +13,18 @@
|
||||
"@rollup/plugin-node-resolve": "15.2.3",
|
||||
"@rollup/plugin-terser": "0.4.4",
|
||||
"@rollup/plugin-typescript": "11.1.5",
|
||||
"@typescript-eslint/eslint-plugin": "6.8.0",
|
||||
"@typescript-eslint/parser": "6.8.0",
|
||||
"@typescript-eslint/eslint-plugin": "6.9.1",
|
||||
"@typescript-eslint/parser": "6.9.1",
|
||||
"covector": "^0.10.2",
|
||||
"eslint": "8.51.0",
|
||||
"eslint": "8.53.0",
|
||||
"eslint-config-prettier": "9.0.0",
|
||||
"eslint-config-standard-with-typescript": "39.1.1",
|
||||
"eslint-plugin-import": "2.28.1",
|
||||
"eslint-plugin-import": "2.29.0",
|
||||
"eslint-plugin-n": "16.2.0",
|
||||
"eslint-plugin-promise": "6.1.1",
|
||||
"eslint-plugin-security": "1.7.1",
|
||||
"prettier": "3.0.3",
|
||||
"rollup": "4.1.4",
|
||||
"rollup": "4.3.0",
|
||||
"typescript": "5.2.2"
|
||||
},
|
||||
"resolutions": {
|
||||
@@ -33,5 +33,12 @@
|
||||
},
|
||||
"engines": {
|
||||
"pnpm": ">=7.33.1"
|
||||
},
|
||||
"pnpm": {
|
||||
"auditConfig": {
|
||||
"ignoreCves": [
|
||||
"CVE-2023-46115"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ _This plugin requires a Rust version of at least **1.70**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
1. Use crates.io and npm (easiest, and requires you to trust that our publishing pipeline worked)
|
||||
1. Use crates.io and npm (easiest and requires you to trust that our publishing pipeline worked)
|
||||
2. Pull sources directly from Github using git tags / revision hashes (most secure)
|
||||
3. Git submodule install this repo in your tauri project and then use file protocol to ingest the source (most secure, but inconvenient to use)
|
||||
3. Git submodule install this repo in your tauri project and then use the file protocol to ingest the source (most secure, but inconvenient to use)
|
||||
|
||||
Install the Core plugin by adding the following to your `Cargo.toml` file:
|
||||
Install the authenticator plugin by adding the following lines to your `Cargo.toml` file:
|
||||
|
||||
`src-tauri/Cargo.toml`
|
||||
|
||||
@@ -50,7 +50,7 @@ yarn add https://github.com/tauri-apps/tauri-plugin-authenticator#v2
|
||||
|
||||
## Usage
|
||||
|
||||
First you need to register the core plugin with Tauri:
|
||||
First, you need to register the authenticator plugin with Tauri:
|
||||
|
||||
`src-tauri/src/main.rs`
|
||||
|
||||
@@ -67,7 +67,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
Afterwards all the plugin's APIs are available through the JavaScript guest bindings:
|
||||
Afterwards, all the plugin's APIs are available through the JavaScript guest bindings:
|
||||
|
||||
```javascript
|
||||
import { Authenticator } from "@tauri-apps/plugin-authenticator";
|
||||
@@ -88,7 +88,7 @@ const domain = "https://tauri.app";
|
||||
const json = await auth.register(challenge, domain);
|
||||
const registerResult = JSON.parse(json);
|
||||
|
||||
// verify te registration was successfull
|
||||
// verify the registration was successful
|
||||
const r2 = await auth.verifyRegistration(
|
||||
challenge,
|
||||
app,
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "2.6.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||
|
||||
@@ -17,4 +17,4 @@ serde_json = { workspace = true }
|
||||
tauri = { workspace = true }
|
||||
log = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
auto-launch = "0.4"
|
||||
auto-launch = "0.5"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "2.6.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.4.1"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||
|
||||
Generated
-4089
File diff suppressed because it is too large
Load Diff
@@ -75,7 +75,7 @@ pub async fn watch(
|
||||
|
||||
let watcher = if let Some(delay) = options.delay_ms {
|
||||
let (tx, rx) = channel();
|
||||
let mut debouncer = new_debouncer(Duration::from_millis(delay), None, tx)?;
|
||||
let mut debouncer = new_debouncer(Duration::from_millis(delay), tx)?;
|
||||
let watcher = debouncer.watcher();
|
||||
for path in &paths {
|
||||
watcher.watch(path, mode)?;
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "2.6.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||
|
||||
@@ -17,7 +17,7 @@ serde_json = { workspace = true }
|
||||
tauri = { workspace = true }
|
||||
log = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
aho-corasick = "1.0"
|
||||
aho-corasick = "1"
|
||||
bincode = "1"
|
||||
tauri-plugin-fs = { path = "../fs", version = "2.0.0-alpha.4" }
|
||||
|
||||
|
||||
@@ -13,13 +13,13 @@
|
||||
|
||||
use aho_corasick::AhoCorasick;
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "protocol-asset")]
|
||||
use tauri::scope::fs::{Event as FsScopeEvent, Scope as FsScope};
|
||||
use tauri::{
|
||||
plugin::{Builder, TauriPlugin},
|
||||
scope::fs::Pattern as GlobPattern,
|
||||
Manager, Runtime,
|
||||
};
|
||||
#[cfg(feature = "protocol-asset")]
|
||||
use tauri::{FsScope, FsScopeEvent};
|
||||
use tauri_plugin_fs::{FsExt, Scope as FsPluginScope, ScopeEvent as FsPluginScopeEvent};
|
||||
|
||||
use std::{
|
||||
@@ -58,7 +58,7 @@ trait ScopeExt {
|
||||
fn forbidden_patterns(&self) -> HashSet<GlobPattern>;
|
||||
}
|
||||
|
||||
impl ScopeExt for &FsPluginScope {
|
||||
impl ScopeExt for FsPluginScope {
|
||||
fn allow_file(&self, path: &Path) {
|
||||
let _ = FsPluginScope::allow_file(self, path);
|
||||
}
|
||||
@@ -85,7 +85,7 @@ impl ScopeExt for &FsPluginScope {
|
||||
}
|
||||
|
||||
#[cfg(feature = "protocol-asset")]
|
||||
impl ScopeExt for &FsScope {
|
||||
impl ScopeExt for FsScope {
|
||||
fn allow_file(&self, path: &Path) {
|
||||
let _ = FsScope::allow_file(self, path);
|
||||
}
|
||||
@@ -171,7 +171,7 @@ fn fix_directory(path_str: &str) -> &Path {
|
||||
path
|
||||
}
|
||||
|
||||
fn allow_path(scope: impl ScopeExt, path: &str) {
|
||||
fn allow_path(scope: &impl ScopeExt, path: &str) {
|
||||
let target_type = detect_scope_type(path);
|
||||
|
||||
match target_type {
|
||||
@@ -189,7 +189,7 @@ fn allow_path(scope: impl ScopeExt, path: &str) {
|
||||
}
|
||||
}
|
||||
|
||||
fn forbid_path(scope: impl ScopeExt, path: &str) {
|
||||
fn forbid_path(scope: &impl ScopeExt, path: &str) {
|
||||
let target_type = detect_scope_type(path);
|
||||
|
||||
match target_type {
|
||||
@@ -205,7 +205,7 @@ fn forbid_path(scope: impl ScopeExt, path: &str) {
|
||||
}
|
||||
}
|
||||
|
||||
fn save_scopes(scope: impl ScopeExt, app_dir: &Path, scope_state_path: &Path) {
|
||||
fn save_scopes(scope: &impl ScopeExt, app_dir: &Path, scope_state_path: &Path) {
|
||||
let scope = Scope {
|
||||
allowed_paths: scope
|
||||
.allowed_patterns()
|
||||
@@ -243,7 +243,8 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
let asset_scope_state_path = app_dir.join(ASSET_SCOPE_STATE_FILENAME);
|
||||
|
||||
if let Some(fs_scope) = fs_scope {
|
||||
let _ = fs_scope.forbid_file(&fs_scope_state_path);}
|
||||
let _ = fs_scope.forbid_file(&fs_scope_state_path);
|
||||
}
|
||||
#[cfg(feature = "protocol-asset")]
|
||||
let _ = asset_protocol_scope.forbid_file(&asset_scope_state_path);
|
||||
|
||||
@@ -271,7 +272,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
// This is needed to fix broken .peristed-scope files in case the app doesn't update the scope itself.
|
||||
save_scopes(fs_scope, &app_dir, &fs_scope_state_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "protocol-asset")]
|
||||
if asset_scope_state_path.exists() {
|
||||
@@ -303,15 +304,15 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "protocol-asset")]
|
||||
{
|
||||
let asset_protocol_scope_ = asset_protocol_scope.clone();
|
||||
asset_protocol_scope.listen(move |event| {
|
||||
if let FsScopeEvent::PathAllowed(_) = event {
|
||||
save_scopes(&asset_protocol_scope_, &app_dir_, &asset_scope_state_path);
|
||||
}
|
||||
});}
|
||||
if let FsScopeEvent::PathAllowed(_) = event {
|
||||
save_scopes(&asset_protocol_scope_, &app_dir_, &asset_scope_state_path);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "2.6.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||
|
||||
@@ -109,13 +109,20 @@ impl<R: Runtime> WindowExt for Window<R> {
|
||||
},
|
||||
#[cfg(feature = "tray-icon")]
|
||||
TrayLeft => {
|
||||
if let Some((tray_x, tray_y)) = tray_position {
|
||||
PhysicalPosition {
|
||||
x: tray_x,
|
||||
y: tray_y - window_size.height,
|
||||
}
|
||||
if let (Some((tray_x, tray_y)), Some((_, _tray_height))) =
|
||||
(tray_position, tray_size)
|
||||
{
|
||||
let y = tray_y - window_size.height;
|
||||
// Choose y value based on the target OS
|
||||
#[cfg(target_os = "windows")]
|
||||
let y = if y < 0 { tray_y + _tray_height } else { y };
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
let y = if y < 0 { tray_y } else { y };
|
||||
|
||||
PhysicalPosition { x: tray_x, y }
|
||||
} else {
|
||||
panic!("tray position not set");
|
||||
panic!("Tray position not set");
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "tray-icon")]
|
||||
@@ -131,11 +138,20 @@ impl<R: Runtime> WindowExt for Window<R> {
|
||||
}
|
||||
#[cfg(feature = "tray-icon")]
|
||||
TrayRight => {
|
||||
if let (Some((tray_x, tray_y)), Some((tray_width, _))) = (tray_position, tray_size)
|
||||
if let (Some((tray_x, tray_y)), Some((tray_width, _tray_height))) =
|
||||
(tray_position, tray_size)
|
||||
{
|
||||
let y = tray_y - window_size.height;
|
||||
// Choose y value based on the target OS
|
||||
#[cfg(target_os = "windows")]
|
||||
let y = if y < 0 { tray_y + _tray_height } else { y };
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
let y = if y < 0 { tray_y } else { y };
|
||||
|
||||
PhysicalPosition {
|
||||
x: tray_x + tray_width,
|
||||
y: tray_y - window_size.height,
|
||||
y,
|
||||
}
|
||||
} else {
|
||||
panic!("Tray position not set");
|
||||
@@ -155,12 +171,19 @@ impl<R: Runtime> WindowExt for Window<R> {
|
||||
}
|
||||
#[cfg(feature = "tray-icon")]
|
||||
TrayCenter => {
|
||||
if let (Some((tray_x, tray_y)), Some((tray_width, _))) = (tray_position, tray_size)
|
||||
if let (Some((tray_x, tray_y)), Some((tray_width, _tray_height))) =
|
||||
(tray_position, tray_size)
|
||||
{
|
||||
PhysicalPosition {
|
||||
x: tray_x + (tray_width / 2) - (window_size.width / 2),
|
||||
y: tray_y - window_size.height,
|
||||
}
|
||||
let x = tray_x + tray_width / 2 - window_size.width / 2;
|
||||
let y = tray_y - window_size.height;
|
||||
// Choose y value based on the target OS
|
||||
#[cfg(target_os = "windows")]
|
||||
let y = if y < 0 { tray_y + _tray_height } else { y };
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
let y = if y < 0 { tray_y } else { y };
|
||||
|
||||
PhysicalPosition { x, y }
|
||||
} else {
|
||||
panic!("Tray position not set");
|
||||
}
|
||||
|
||||
@@ -19,11 +19,11 @@ tauri = { workspace = true }
|
||||
log = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
futures-core = "0.3"
|
||||
sqlx = { version = "0.7", features = [ "runtime-tokio-rustls", "json", "time" ] }
|
||||
sqlx = { version = "0.7", features = ["json", "time"] }
|
||||
time = "0.3"
|
||||
tokio = { version = "1", features = [ "sync" ] }
|
||||
|
||||
[features]
|
||||
sqlite = [ "sqlx/sqlite" ]
|
||||
mysql = [ "sqlx/mysql" ]
|
||||
postgres = [ "sqlx/postgres" ]
|
||||
sqlite = ["sqlx/sqlite", "sqlx/runtime-tokio"]
|
||||
mysql = ["sqlx/mysql", "sqlx/runtime-tokio-rustls"]
|
||||
postgres = ["sqlx/postgres", "sqlx/runtime-tokio-rustls"]
|
||||
|
||||
@@ -114,7 +114,6 @@ export default class Database {
|
||||
values: bindValues ?? [],
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
lastInsertId,
|
||||
rowsAffected,
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "2.6.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||
|
||||
@@ -21,7 +21,14 @@ pub(crate) fn to_json(v: MySqlValueRef) -> Result<JsonValue, Error> {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"FLOAT" | "DOUBLE" => {
|
||||
"FLOAT" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<f32>() {
|
||||
JsonValue::from(v)
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"DOUBLE" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<f64>() {
|
||||
JsonValue::from(v)
|
||||
} else {
|
||||
|
||||
@@ -21,14 +21,35 @@ pub(crate) fn to_json(v: PgValueRef) -> Result<JsonValue, Error> {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"FLOAT4" | "FLOAT8" => {
|
||||
"FLOAT4" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<f32>() {
|
||||
JsonValue::from(v)
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"FLOAT8" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<f64>() {
|
||||
JsonValue::from(v)
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"INT2" | "INT4" | "INT8" => {
|
||||
"INT2" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<i16>() {
|
||||
JsonValue::Number(v.into())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"INT4" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<i32>() {
|
||||
JsonValue::Number(v.into())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"INT8" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<i64>() {
|
||||
JsonValue::Number(v.into())
|
||||
} else {
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "2.6.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||
|
||||
@@ -22,6 +22,15 @@ iota-crypto = "0.23"
|
||||
hex = "0.4"
|
||||
zeroize = { version = "1", features = [ "zeroize_derive" ] }
|
||||
|
||||
# kdf dependencies
|
||||
rust-argon2 = { version = "1", optional = true }
|
||||
rand_chacha = { version = "0.3.1", optional = true }
|
||||
rand_core = { version = "0.6.4", features = ["getrandom"], optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.8"
|
||||
rusty-fork = "0.3"
|
||||
|
||||
[features]
|
||||
default = ["kdf"]
|
||||
kdf = ["dep:rust-argon2", "dep:rand_chacha", "dep:rand_core"]
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "2.6.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use rand_chacha::ChaCha20Rng;
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use std::path::Path;
|
||||
|
||||
/// NOTE: Hash supplied to Stronghold must be 32bits long.
|
||||
/// This is a current limitation of Stronghold.
|
||||
const HASH_LENGTH: usize = 32;
|
||||
|
||||
pub struct KeyDerivation {}
|
||||
|
||||
impl KeyDerivation {
|
||||
/// Will create a key from [`password`] and a generated salt.
|
||||
/// Salt will be generated to file [`salt_path`] or taken from it
|
||||
/// if file already exists
|
||||
pub fn argon2(password: &str, salt_path: &Path) -> Vec<u8> {
|
||||
let mut salt = [0u8; HASH_LENGTH];
|
||||
create_or_get_salt(&mut salt, salt_path);
|
||||
|
||||
argon2::hash_raw(password.as_bytes(), &salt, &Default::default())
|
||||
.expect("Failed to generate hash for password")
|
||||
}
|
||||
}
|
||||
|
||||
fn create_or_get_salt(salt: &mut [u8], salt_path: &Path) {
|
||||
if salt_path.is_file() {
|
||||
// Get existing salt
|
||||
let tmp = std::fs::read(salt_path).unwrap();
|
||||
salt.clone_from_slice(&tmp);
|
||||
} else {
|
||||
// Generate new salt
|
||||
let mut gen = ChaCha20Rng::from_entropy();
|
||||
gen.fill_bytes(salt);
|
||||
std::fs::write(salt_path, salt).expect("Failed to write salt for Stronghold")
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,9 @@ use tauri::{
|
||||
};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
#[cfg(feature = "kdf")]
|
||||
pub mod kdf;
|
||||
|
||||
pub mod stronghold;
|
||||
|
||||
type PasswordHashFn = dyn Fn(&str) -> Vec<u8> + Send + Sync;
|
||||
@@ -407,27 +410,72 @@ fn get_client(
|
||||
}
|
||||
}
|
||||
|
||||
enum PasswordHashFunctionKind {
|
||||
#[cfg(feature = "kdf")]
|
||||
Argon2(PathBuf),
|
||||
Custom(Box<PasswordHashFn>),
|
||||
}
|
||||
|
||||
pub struct Builder {
|
||||
password_hash_function: Box<PasswordHashFn>,
|
||||
password_hash_function: PasswordHashFunctionKind,
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
pub fn new<F: Fn(&str) -> Vec<u8> + Send + Sync + 'static>(password_hash_function: F) -> Self {
|
||||
Self {
|
||||
password_hash_function: Box::new(password_hash_function),
|
||||
password_hash_function: PasswordHashFunctionKind::Custom(Box::new(
|
||||
password_hash_function,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes [`Self`] with argon2 as password hash function.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// tauri::Builder::default()
|
||||
/// .setup(|app| {
|
||||
/// let salt_path = app
|
||||
/// .path_resolver()
|
||||
/// .app_local_data_dir()
|
||||
/// .expect("could not resolve app local data path")
|
||||
/// .join("salt.txt");
|
||||
/// app.handle().plugin(tauri_plugin_stronghold::Builder::with_argon2(&salt_path).build())?;
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// ```
|
||||
#[cfg(feature = "kdf")]
|
||||
pub fn with_argon2(salt_path: &std::path::Path) -> Self {
|
||||
Self {
|
||||
password_hash_function: PasswordHashFunctionKind::Argon2(salt_path.to_owned()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build<R: Runtime>(self) -> TauriPlugin<R> {
|
||||
let password_hash_function = self.password_hash_function;
|
||||
|
||||
PluginBuilder::new("stronghold")
|
||||
let plugin_builder = PluginBuilder::new("stronghold")
|
||||
.js_init_script(include_str!("api-iife.js").to_string())
|
||||
.setup(move |app, _api| {
|
||||
app.manage(StrongholdCollection::default());
|
||||
app.manage(PasswordHashFunction(password_hash_function));
|
||||
app.manage(PasswordHashFunction(match password_hash_function {
|
||||
#[cfg(feature = "kdf")]
|
||||
PasswordHashFunctionKind::Argon2(path) => {
|
||||
Box::new(move |p| kdf::KeyDerivation::argon2(p, &path))
|
||||
}
|
||||
PasswordHashFunctionKind::Custom(f) => f,
|
||||
}));
|
||||
Ok(())
|
||||
})
|
||||
});
|
||||
|
||||
Builder::invoke_stronghold_handlers_and_build(plugin_builder)
|
||||
}
|
||||
|
||||
fn invoke_stronghold_handlers_and_build<R: Runtime>(
|
||||
builder: PluginBuilder<R>,
|
||||
) -> TauriPlugin<R> {
|
||||
builder
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
initialize,
|
||||
destroy,
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "2.6.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||
|
||||
@@ -21,7 +21,10 @@ use tauri::{
|
||||
plugin::{Builder as PluginBuilder, TauriPlugin},
|
||||
Runtime,
|
||||
};
|
||||
use tokio::{fs::File, io::AsyncWriteExt};
|
||||
use tokio::{
|
||||
fs::File,
|
||||
io::{AsyncWriteExt, BufWriter},
|
||||
};
|
||||
use tokio_util::codec::{BytesCodec, FramedRead};
|
||||
|
||||
use read_progress_stream::ReadProgressStream;
|
||||
@@ -74,7 +77,7 @@ async fn download(
|
||||
let response = request.send().await?;
|
||||
let total = response.content_length().unwrap_or(0);
|
||||
|
||||
let mut file = File::create(file_path).await?;
|
||||
let mut file = BufWriter::new(File::create(file_path).await?);
|
||||
let mut stream = response.bytes_stream();
|
||||
|
||||
while let Some(chunk) = stream.try_next().await? {
|
||||
@@ -84,6 +87,7 @@ async fn download(
|
||||
total,
|
||||
});
|
||||
}
|
||||
file.flush().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
"tauri": "tauri"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-static": "2.0.3",
|
||||
"@sveltejs/kit": "1.26.0",
|
||||
"@sveltejs/adapter-auto": "2.1.1",
|
||||
"@sveltejs/kit": "1.27.3",
|
||||
"@tauri-apps/cli": "2.0.0-alpha.17",
|
||||
"svelte": "4.2.2",
|
||||
"svelte-check": "3.5.2",
|
||||
|
||||
@@ -50,6 +50,10 @@ export default class WebSocket {
|
||||
listeners.forEach((l) => l(message));
|
||||
};
|
||||
|
||||
if (config?.headers) {
|
||||
config.headers = Array.from(new Headers(config.headers).entries());
|
||||
}
|
||||
|
||||
return await invoke<number>("plugin:websocket|connect", {
|
||||
url,
|
||||
onMessage,
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "2.6.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||
|
||||
@@ -1 +1 @@
|
||||
if("__TAURI__"in window){var __TAURI_WEBSOCKET__=function(){"use strict";function e(e,t,r,n){if("a"===r&&!n)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!n:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===r?n:"a"===r?n.call(e):n?n.value:t.get(e)}var t;"function"==typeof SuppressedError&&SuppressedError;class r{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,t.set(this,(()=>{})),this.id=function(e,t=!1){return window.__TAURI_INTERNALS__.transformCallback(e,t)}((r=>{e(this,t,"f").call(this,r)}))}set onmessage(e){!function(e,t,r,n,s){if("m"===n)throw new TypeError("Private method is not writable");if("a"===n&&!s)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof t?e!==t||!s:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");"a"===n?s.call(e,r):s?s.value=r:t.set(e,r)}(this,t,e,"f")}get onmessage(){return e(this,t,"f")}toJSON(){return`__CHANNEL__:${this.id}`}}async function n(e,t={},r){return window.__TAURI_INTERNALS__.invoke(e,t,r)}t=new WeakMap;class s{constructor(e,t){this.id=e,this.listeners=t}static async connect(e,t){const i=[],a=new r;return a.onmessage=e=>{i.forEach((t=>t(e)))},await n("plugin:websocket|connect",{url:e,onMessage:a,config:t}).then((e=>new s(e,i)))}addListener(e){this.listeners.push(e)}async send(e){let t;if("string"==typeof e)t={type:"Text",data:e};else if("object"==typeof e&&"type"in e)t=e;else{if(!Array.isArray(e))throw new Error("invalid `message` type, expected a `{ type: string, data: any }` object, a string or a numeric array");t={type:"Binary",data:e}}return await n("plugin:websocket|send",{id:this.id,message:t})}async disconnect(){return await this.send({type:"Close",data:{code:1e3,reason:"Disconnected by client"}})}}return s}();Object.defineProperty(window.__TAURI__,"websocket",{value:__TAURI_WEBSOCKET__})}
|
||||
if("__TAURI__"in window){var __TAURI_WEBSOCKET__=function(){"use strict";function e(e,t,r,n){if("a"===r&&!n)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!n:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===r?n:"a"===r?n.call(e):n?n.value:t.get(e)}var t;"function"==typeof SuppressedError&&SuppressedError;class r{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,t.set(this,(()=>{})),this.id=function(e,t=!1){return window.__TAURI_INTERNALS__.transformCallback(e,t)}((r=>{e(this,t,"f").call(this,r)}))}set onmessage(e){!function(e,t,r,n,s){if("m"===n)throw new TypeError("Private method is not writable");if("a"===n&&!s)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof t?e!==t||!s:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");"a"===n?s.call(e,r):s?s.value=r:t.set(e,r)}(this,t,e,"f")}get onmessage(){return e(this,t,"f")}toJSON(){return`__CHANNEL__:${this.id}`}}async function n(e,t={},r){return window.__TAURI_INTERNALS__.invoke(e,t,r)}t=new WeakMap;class s{constructor(e,t){this.id=e,this.listeners=t}static async connect(e,t){const a=[],i=new r;return i.onmessage=e=>{a.forEach((t=>t(e)))},(null==t?void 0:t.headers)&&(t.headers=Array.from(new Headers(t.headers).entries())),await n("plugin:websocket|connect",{url:e,onMessage:i,config:t}).then((e=>new s(e,a)))}addListener(e){this.listeners.push(e)}async send(e){let t;if("string"==typeof e)t={type:"Text",data:e};else if("object"==typeof e&&"type"in e)t=e;else{if(!Array.isArray(e))throw new Error("invalid `message` type, expected a `{ type: string, data: any }` object, a string or a numeric array");t={type:"Binary",data:e}}return await n("plugin:websocket|send",{id:this.id,message:t})}async disconnect(){return await this.send({type:"Close",data:{code:1e3,reason:"Disconnected by client"}})}}return s}();Object.defineProperty(window.__TAURI__,"websocket",{value:__TAURI_WEBSOCKET__})}
|
||||
|
||||
@@ -29,6 +29,9 @@ use tokio_tungstenite::{
|
||||
};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use tauri::http::header::{HeaderName, HeaderValue};
|
||||
use tokio_tungstenite::tungstenite::client::IntoClientRequest;
|
||||
|
||||
type Id = u32;
|
||||
type WebSocket = WebSocketStream<MaybeTlsStream<TcpStream>>;
|
||||
@@ -41,6 +44,10 @@ enum Error {
|
||||
Websocket(#[from] tokio_tungstenite::tungstenite::Error),
|
||||
#[error("connection not found for the given id: {0}")]
|
||||
ConnectionNotFound(Id),
|
||||
#[error(transparent)]
|
||||
InvalidHeaderValue(#[from] tokio_tungstenite::tungstenite::http::header::InvalidHeaderValue),
|
||||
#[error(transparent)]
|
||||
InvalidHeaderName(#[from] tokio_tungstenite::tungstenite::http::header::InvalidHeaderName),
|
||||
}
|
||||
|
||||
impl Serialize for Error {
|
||||
@@ -108,7 +115,17 @@ async fn connect<R: Runtime>(
|
||||
config: Option<ConnectionConfig>,
|
||||
) -> Result<Id> {
|
||||
let id = rand::random();
|
||||
let (ws_stream, _) = connect_async_with_config(url, config.map(Into::into), false).await?;
|
||||
let mut request = url.into_client_request()?;
|
||||
|
||||
if let Some(headers) = config.as_ref().and_then(|c| c.headers.as_ref()) {
|
||||
for (k, v) in headers {
|
||||
let header_name = HeaderName::from_str(k.as_str())?;
|
||||
let header_value = HeaderValue::from_str(v.as_str())?;
|
||||
request.headers_mut().insert(header_name, header_value);
|
||||
}
|
||||
}
|
||||
|
||||
let (ws_stream, _) = connect_async_with_config(request, config.map(Into::into), false).await?;
|
||||
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let (write, read) = ws_stream.split();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import { invoke } from "@tauri-apps/api/primitives";
|
||||
import { getCurrent } from "@tauri-apps/api/window";
|
||||
import { WindowLabel, getCurrent } from "@tauri-apps/api/window";
|
||||
|
||||
export enum StateFlags {
|
||||
SIZE = 1 << 0,
|
||||
@@ -19,19 +19,17 @@ export enum StateFlags {
|
||||
* Save the state of all open windows to disk.
|
||||
*/
|
||||
async function saveWindowState(flags: StateFlags): Promise<void> {
|
||||
return invoke("plugin:window-state|save_window_state", {
|
||||
flags,
|
||||
});
|
||||
return invoke("plugin:window-state|save_window_state", { flags });
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the state for the specified window from disk.
|
||||
*/
|
||||
async function restoreState(label: string, flags: StateFlags): Promise<void> {
|
||||
return invoke("plugin:window-state|restore_state", {
|
||||
label,
|
||||
flags,
|
||||
});
|
||||
async function restoreState(
|
||||
label: WindowLabel,
|
||||
flags: StateFlags,
|
||||
): Promise<void> {
|
||||
return invoke("plugin:window-state|restore_state", { label, flags });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "2.6.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||
|
||||
Generated
+579
-590
File diff suppressed because it is too large
Load Diff
@@ -24,7 +24,7 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "2.6.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user