Merge branch 'v2' into feat/shell-show-item-in-dir

This commit is contained in:
amrbashir
2024-10-30 00:37:20 +03:00
919 changed files with 42486 additions and 35602 deletions
-1
View File
@@ -1 +0,0 @@
node_modules
-44
View File
@@ -1,44 +0,0 @@
# Changelog
## \[2.0.0-beta.1]
- [`569defb`](https://github.com/tauri-apps/plugins-workspace/commit/569defbe9492e38938554bb7bdc1be9151456d21) Update to tauri beta.4.
## \[2.0.0-beta.0]
- [`d198c01`](https://github.com/tauri-apps/plugins-workspace/commit/d198c014863ee260cb0de88a14b7fc4356ef7474)([#862](https://github.com/tauri-apps/plugins-workspace/pull/862)) Update to tauri beta.
## \[2.0.0-alpha.5]
- [`387c2f9`](https://github.com/tauri-apps/plugins-workspace/commit/387c2f9e0ce4c75c07ffa3fd76391a25b58f5daf)([#802](https://github.com/tauri-apps/plugins-workspace/pull/802)) Update to @tauri-apps/api v2.0.0-alpha.13.
## \[2.0.0-alpha.4]
- [`387c2f9`](https://github.com/tauri-apps/plugins-workspace/commit/387c2f9e0ce4c75c07ffa3fd76391a25b58f5daf)([#802](https://github.com/tauri-apps/plugins-workspace/pull/802)) Update to @tauri-apps/api v2.0.0-alpha.12.
## \[2.0.0-alpha.3]
- [`e438e0a`](https://github.com/tauri-apps/plugins-workspace/commit/e438e0a62d4b430a5159f05f13ecd397dd891a0d)([#676](https://github.com/tauri-apps/plugins-workspace/pull/676)) Update to @tauri-apps/api v2.0.0-alpha.11.
## \[2.0.0-alpha.2]
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.9.
## \[2.0.0-alpha.2]
- [`4e2cef9`](https://github.com/tauri-apps/plugins-workspace/commit/4e2cef9b702bbbb9cf4ee17de50791cb21f1b2a4)([#593](https://github.com/tauri-apps/plugins-workspace/pull/593)) Update to alpha.12.
## \[2.0.0-alpha.1]
- [`d74fc0a`](https://github.com/tauri-apps/plugins-workspace/commit/d74fc0a097996e90a37be8f57d50b7d1f6ca616f)([#555](https://github.com/tauri-apps/plugins-workspace/pull/555)) Update to alpha.11.
## \[2.0.0-alpha.0]
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
te to alpha.11.
## \[2.0.0-alpha.0]
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
ae67\`]\(https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
-37
View File
@@ -1,37 +0,0 @@
[package]
name = "tauri-plugin-authenticator"
version = "2.0.0-beta.1"
description = "Use hardware security-keys in your Tauri App."
authors = { workspace = true }
license = { workspace = true }
edition = { workspace = true }
rust-version = { workspace = true }
links = "tauri-plugin-authenticator"
[package.metadata.docs.rs]
rustc-args = [ "--cfg", "docsrs" ]
rustdoc-args = [ "--cfg", "docsrs" ]
[build-dependencies]
tauri-plugin = { workspace = true, features = [ "build" ] }
[dependencies]
serde = { workspace = true }
serde_json = { workspace = true }
tauri = { workspace = true }
log = { workspace = true }
thiserror = { workspace = true }
[target."cfg(not(any(target_os = \"android\", target_os = \"ios\")))".dependencies]
authenticator = "0.3.1"
once_cell = "1"
sha2 = "0.10"
base64 = "0.21"
chrono = "0.4"
bytes = "1"
byteorder = "1"
openssl = "0.10"
[dev-dependencies]
rand = "0.8"
rusty-fork = "0.3"
-143
View File
@@ -1,143 +0,0 @@
![plugin-authenticator](https://github.com/tauri-apps/plugins-workspace/raw/v2/plugins/authenticator/banner.png)
Use hardware security-keys in your Tauri App.
- Supported platforms: Windows, Linux, FreeBSD, NetBSD, OpenBSD, and macOS.
## Install
_This plugin requires a Rust version of at least **1.75**_
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)
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 the file protocol to ingest the source (most secure, but inconvenient to use)
Install the authenticator plugin by adding the following lines to your `Cargo.toml` file:
`src-tauri/Cargo.toml`
```toml
# you can add the dependencies on the `[dependencies]` section if you do not target mobile
[target."cfg(not(any(target_os = \"android\", target_os = \"ios\")))".dependencies]
tauri-plugin-authenticator = "2.0.0-beta"
# alternatively with Git:
tauri-plugin-authenticator = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
```
You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
> Note: Since most JavaScript package managers are unable to install packages from git monorepos we provide read-only mirrors of each plugin. This makes installation option 2 more ergonomic to use.
```sh
pnpm add @tauri-apps/plugin-authenticator
# or
npm add @tauri-apps/plugin-authenticator
# or
yarn add @tauri-apps/plugin-authenticator
```
Alternatively with Git:
```sh
pnpm add https://github.com/tauri-apps/tauri-plugin-authenticator#v2
# or
npm add https://github.com/tauri-apps/tauri-plugin-authenticator#v2
# or
yarn add https://github.com/tauri-apps/tauri-plugin-authenticator#v2
```
## Usage
First, you need to register the authenticator plugin with Tauri:
`src-tauri/src/main.rs`
```rust
fn main() {
tauri::Builder::default()
.setup(|app| {
#[cfg(desktop)]
app.handle().plugin(tauri_plugin_authenticator::init())?;
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
```
Afterwards, all the plugin's APIs are available through the JavaScript guest bindings:
```javascript
import { Authenticator } from "@tauri-apps/plugin-authenticator";
const auth = new Authenticator();
auth.init(); // initialize transports
// generate a 32-bytes long random challenge
const arr = new Uint32Array(32);
window.crypto.getRandomValues(arr);
const b64 = btoa(String.fromCharCode.apply(null, arr));
// web-safe base64
const challenge = b64.replace(/\+/g, "-").replace(/\//g, "_");
const domain = "https://tauri.app";
// attempt to register with the security key
const json = await auth.register(challenge, domain);
const registerResult = JSON.parse(json);
// verify the registration was successful
const r2 = await auth.verifyRegistration(
challenge,
app,
registerResult.registerData,
registerResult.clientData,
);
const j2 = JSON.parse(r2);
// sign some data
const json = await auth.sign(challenge, app, keyHandle);
const signData = JSON.parse(json);
// verify the signature again
const counter = await auth.verifySignature(
challenge,
app,
signData.signData,
clientData,
keyHandle,
pubkey,
);
if (counter && counter > 0) {
console.log("SUCCESS!");
}
```
## Contributing
PRs accepted. Please make sure to read the Contributing Guide before making a pull request.
## Partners
<table>
<tbody>
<tr>
<td align="center" valign="middle">
<a href="https://crabnebula.dev" target="_blank">
<img src="https://github.com/tauri-apps/plugins-workspace/raw/v2/.github/sponsors/crabnebula.svg" alt="CrabNebula" width="283">
</a>
</td>
</tr>
</tbody>
</table>
For the complete list of sponsors please visit our [website](https://tauri.app#sponsors) and [Open Collective](https://opencollective.com/tauri).
## License
Code: (c) 2015 - Present - The Tauri Programme within The Commons Conservancy.
MIT or MIT/Apache 2.0 where applicable.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

-15
View File
@@ -1,15 +0,0 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
const COMMANDS: &[&str] = &[
"init_auth",
"register",
"verify_registration",
"sign",
"verify_signature",
];
fn main() {
tauri_plugin::Builder::new(COMMANDS).build();
}
-64
View File
@@ -1,64 +0,0 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
import { invoke } from "@tauri-apps/api/core";
export class Authenticator {
async init(): Promise<void> {
return await invoke("plugin:authenticator|init_auth");
}
async register(challenge: string, application: string): Promise<string> {
return await invoke("plugin:authenticator|register", {
timeout: 10000,
challenge,
application,
});
}
async verifyRegistration(
challenge: string,
application: string,
registerData: string,
clientData: string,
): Promise<string> {
return await invoke("plugin:authenticator|verify_registration", {
challenge,
application,
registerData,
clientData,
});
}
async sign(
challenge: string,
application: string,
keyHandle: string,
): Promise<string> {
return await invoke("plugin:authenticator|sign", {
timeout: 10000,
challenge,
application,
keyHandle,
});
}
async verifySignature(
challenge: string,
application: string,
signData: string,
clientData: string,
keyHandle: string,
pubkey: string,
): Promise<number> {
return await invoke("plugin:authenticator|verify_signature", {
challenge,
application,
signData,
clientData,
keyHandle,
pubkey,
});
}
}
@@ -1,13 +0,0 @@
# Automatically generated - DO NOT EDIT!
"$schema" = "../../schemas/schema.json"
[[permission]]
identifier = "allow-init-auth"
description = "Enables the init_auth command without any pre-configured scope."
commands.allow = ["init_auth"]
[[permission]]
identifier = "deny-init-auth"
description = "Denies the init_auth command without any pre-configured scope."
commands.deny = ["init_auth"]
@@ -1,13 +0,0 @@
# Automatically generated - DO NOT EDIT!
"$schema" = "../../schemas/schema.json"
[[permission]]
identifier = "allow-sign"
description = "Enables the sign command without any pre-configured scope."
commands.allow = ["sign"]
[[permission]]
identifier = "deny-sign"
description = "Denies the sign command without any pre-configured scope."
commands.deny = ["sign"]
@@ -1,13 +0,0 @@
# Automatically generated - DO NOT EDIT!
"$schema" = "../../schemas/schema.json"
[[permission]]
identifier = "allow-verify-registration"
description = "Enables the verify_registration command without any pre-configured scope."
commands.allow = ["verify_registration"]
[[permission]]
identifier = "deny-verify-registration"
description = "Denies the verify_registration command without any pre-configured scope."
commands.deny = ["verify_registration"]
@@ -1,13 +0,0 @@
# Automatically generated - DO NOT EDIT!
"$schema" = "../../schemas/schema.json"
[[permission]]
identifier = "allow-verify-signature"
description = "Enables the verify_signature command without any pre-configured scope."
commands.allow = ["verify_signature"]
[[permission]]
identifier = "deny-verify-signature"
description = "Denies the verify_signature command without any pre-configured scope."
commands.deny = ["verify_signature"]
@@ -1,42 +0,0 @@
# Permissions
## allow-init-auth
Enables the init_auth command without any pre-configured scope.
## deny-init-auth
Denies the init_auth command without any pre-configured scope.
## allow-register
Enables the register command without any pre-configured scope.
## deny-register
Denies the register command without any pre-configured scope.
## allow-sign
Enables the sign command without any pre-configured scope.
## deny-sign
Denies the sign command without any pre-configured scope.
## allow-verify-registration
Enables the verify_registration command without any pre-configured scope.
## deny-verify-registration
Denies the verify_registration command without any pre-configured scope.
## allow-verify-signature
Enables the verify_signature command without any pre-configured scope.
## deny-verify-signature
Denies the verify_signature command without any pre-configured scope.
-1
View File
@@ -1 +0,0 @@
if("__TAURI__"in window){var __TAURI_PLUGIN_AUTHENTICATOR__=function(t){"use strict";async function i(t,i={},a){return window.__TAURI_INTERNALS__.invoke(t,i,a)}"function"==typeof SuppressedError&&SuppressedError;return t.Authenticator=class{async init(){return await i("plugin:authenticator|init_auth")}async register(t,a){return await i("plugin:authenticator|register",{timeout:1e4,challenge:t,application:a})}async verifyRegistration(t,a,e,n){return await i("plugin:authenticator|verify_registration",{challenge:t,application:a,registerData:e,clientData:n})}async sign(t,a,e){return await i("plugin:authenticator|sign",{timeout:1e4,challenge:t,application:a,keyHandle:e})}async verifySignature(t,a,e,n,r,u){return await i("plugin:authenticator|verify_signature",{challenge:t,application:a,signData:e,clientData:n,keyHandle:r,pubkey:u})}},t}({});Object.defineProperty(window.__TAURI__,"authenticator",{value:__TAURI_PLUGIN_AUTHENTICATOR__})}
-212
View File
@@ -1,212 +0,0 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use authenticator::{
authenticatorservice::AuthenticatorService, statecallback::StateCallback,
AuthenticatorTransports, KeyHandle, RegisterFlags, SignFlags, StatusUpdate,
};
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
use once_cell::sync::Lazy;
use serde::Serialize;
use sha2::{Digest, Sha256};
use std::io;
use std::sync::mpsc::channel;
use std::{convert::Into, sync::Mutex};
static MANAGER: Lazy<Mutex<AuthenticatorService>> = Lazy::new(|| {
let manager = AuthenticatorService::new().expect("The auth service should initialize safely");
Mutex::new(manager)
});
pub fn init_usb() {
let mut manager = MANAGER.lock().unwrap();
// theres also "add_detected_transports()" in the docs?
manager.add_u2f_usb_hid_platform_transports();
}
#[derive(Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Registration {
pub key_handle: String,
pub pubkey: String,
pub register_data: String,
pub client_data: String,
}
pub fn register(application: String, timeout: u64, challenge: String) -> crate::Result<String> {
let (chall_bytes, app_bytes, client_data_string) =
format_client_data(application.as_str(), challenge.as_str());
// log the status rx?
let (status_tx, _status_rx) = channel::<StatusUpdate>();
let mut manager = MANAGER.lock().unwrap();
let (register_tx, register_rx) = channel();
let callback = StateCallback::new(Box::new(move |rv| {
register_tx.send(rv).unwrap();
}));
let res = manager.register(
RegisterFlags::empty(),
timeout,
chall_bytes,
app_bytes,
vec![],
status_tx,
callback,
);
match res {
Ok(_r) => {
let register_result = register_rx
.recv()
.expect("Problem receiving, unable to continue");
if let Err(e) = register_result {
return Err(e.into());
}
let (register_data, device_info) = register_result.unwrap(); // error already has been checked
// println!("Register result: {}", base64::encode(&register_data));
println!("Device info: {}", &device_info);
let (key_handle, public_key) =
_u2f_get_key_handle_and_public_key_from_register_response(&register_data).unwrap();
let key_handle_base64 = URL_SAFE_NO_PAD.encode(key_handle);
let public_key_base64 = URL_SAFE_NO_PAD.encode(public_key);
let register_data_base64 = URL_SAFE_NO_PAD.encode(&register_data);
println!("Key Handle: {}", &key_handle_base64);
println!("Public Key: {}", &public_key_base64);
// Ok(base64::encode(&register_data))
// Ok(key_handle_base64)
let res = serde_json::to_string(&Registration {
key_handle: key_handle_base64,
pubkey: public_key_base64,
register_data: register_data_base64,
client_data: client_data_string,
})?;
Ok(res)
}
Err(e) => Err(e.into()),
}
}
#[derive(Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Signature {
pub key_handle: String,
pub sign_data: String,
}
pub fn sign(
application: String,
timeout: u64,
challenge: String,
key_handle: String,
) -> crate::Result<String> {
let credential = match URL_SAFE_NO_PAD.decode(key_handle) {
Ok(v) => v,
Err(e) => {
return Err(e.into());
}
};
let key_handle = KeyHandle {
credential,
transports: AuthenticatorTransports::empty(),
};
let (chall_bytes, app_bytes, _) = format_client_data(application.as_str(), challenge.as_str());
let (sign_tx, sign_rx) = channel();
let callback = StateCallback::new(Box::new(move |rv| {
sign_tx.send(rv).unwrap();
}));
// log the status rx?
let (status_tx, _status_rx) = channel::<StatusUpdate>();
let mut manager = MANAGER.lock().unwrap();
let res = manager.sign(
SignFlags::empty(),
timeout,
chall_bytes,
vec![app_bytes],
vec![key_handle],
status_tx,
callback,
);
match res {
Ok(_v) => {
let sign_result = sign_rx
.recv()
.expect("Problem receiving, unable to continue");
if let Err(e) = sign_result {
return Err(e.into());
}
let (_, handle_used, sign_data, device_info) = sign_result.unwrap();
let sig = URL_SAFE_NO_PAD.encode(sign_data);
println!("Sign result: {sig}");
println!("Key handle used: {}", URL_SAFE_NO_PAD.encode(&handle_used));
println!("Device info: {}", &device_info);
println!("Done.");
let res = serde_json::to_string(&Signature {
sign_data: sig,
key_handle: URL_SAFE_NO_PAD.encode(&handle_used),
})?;
Ok(res)
}
Err(e) => Err(e.into()),
}
}
fn format_client_data(application: &str, challenge: &str) -> (Vec<u8>, Vec<u8>, String) {
let d =
format!(r#"{{"challenge": "{challenge}", "version": "U2F_V2", "appId": "{application}"}}"#);
let mut challenge = Sha256::new();
challenge.update(d.as_bytes());
let chall_bytes = challenge.finalize().to_vec();
let mut app = Sha256::new();
app.update(application.as_bytes());
let app_bytes = app.finalize().to_vec();
(chall_bytes, app_bytes, d)
}
fn _u2f_get_key_handle_and_public_key_from_register_response(
register_response: &[u8],
) -> io::Result<(Vec<u8>, Vec<u8>)> {
if register_response[0] != 0x05 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Reserved byte not set correctly",
));
}
// 1: reserved
// 65: public key
// 1: key handle length
// key handle
// x.509 cert
// sig
let key_handle_len = register_response[66] as usize;
let mut public_key = register_response.to_owned();
let mut key_handle = public_key.split_off(67);
let _attestation = key_handle.split_off(key_handle_len);
// remove fist (reserved) and last (handle len) bytes
let pk: Vec<u8> = public_key[1..public_key.len() - 1].to_vec();
Ok((key_handle, pk))
}
-90
View File
@@ -1,90 +0,0 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
//! [![](https://github.com/tauri-apps/plugins-workspace/raw/v2/plugins/authenticator/banner.png)](https://github.com/tauri-apps/plugins-workspace/tree/v2/plugins/authenticator)
//!
//! Use hardware security-keys in your Tauri App.
//!
//! - Supported platforms: Windows, Linux, FreeBSD, NetBSD, OpenBSD, and macOS.
#![doc(
html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png",
html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png"
)]
#![cfg(not(any(target_os = "android", target_os = "ios")))]
mod auth;
mod error;
mod u2f;
mod u2f_crate;
use tauri::{
plugin::{Builder as PluginBuilder, TauriPlugin},
Runtime,
};
pub use error::Error;
type Result<T> = std::result::Result<T, Error>;
#[tauri::command]
fn init_auth() {
auth::init_usb();
}
#[tauri::command]
fn register(timeout: u64, challenge: String, application: String) -> crate::Result<String> {
auth::register(application, timeout, challenge)
}
#[tauri::command]
fn verify_registration(
challenge: String,
application: String,
register_data: String,
client_data: String,
) -> crate::Result<String> {
u2f::verify_registration(application, challenge, register_data, client_data)
}
#[tauri::command]
fn sign(
timeout: u64,
challenge: String,
application: String,
key_handle: String,
) -> crate::Result<String> {
auth::sign(application, timeout, challenge, key_handle)
}
#[tauri::command]
fn verify_signature(
challenge: String,
application: String,
sign_data: String,
client_data: String,
key_handle: String,
pubkey: String,
) -> crate::Result<u32> {
u2f::verify_signature(
application,
challenge,
sign_data,
client_data,
key_handle,
pubkey,
)
}
pub fn init<R: Runtime>() -> TauriPlugin<R> {
PluginBuilder::new("authenticator")
.js_init_script(include_str!("api-iife.js").to_string())
.invoke_handler(tauri::generate_handler![
init_auth,
register,
verify_registration,
sign,
verify_signature
])
.build()
}
-105
View File
@@ -1,105 +0,0 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use crate::u2f_crate::messages::*;
use crate::u2f_crate::protocol::*;
use crate::u2f_crate::register::*;
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
use chrono::prelude::*;
use serde::Serialize;
use std::convert::Into;
static VERSION: &str = "U2F_V2";
pub fn make_challenge(app_id: &str, challenge_bytes: Vec<u8>) -> Challenge {
let utc: DateTime<Utc> = Utc::now();
Challenge {
challenge: URL_SAFE_NO_PAD.encode(challenge_bytes),
timestamp: format!("{utc:?}"),
app_id: app_id.to_string(),
}
}
#[derive(Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct RegistrationVerification {
pub key_handle: String,
pub pubkey: String,
pub device_name: Option<String>,
}
pub fn verify_registration(
app_id: String,
challenge: String,
register_data: String,
client_data: String,
) -> crate::Result<String> {
let challenge_bytes = URL_SAFE_NO_PAD.decode(challenge)?;
let challenge = make_challenge(&app_id, challenge_bytes);
let client_data_bytes: Vec<u8> = client_data.as_bytes().into();
let client_data_base64 = URL_SAFE_NO_PAD.encode(client_data_bytes);
let client = U2f::new(app_id);
match client.register_response(
challenge,
RegisterResponse {
registration_data: register_data,
client_data: client_data_base64,
version: VERSION.to_string(),
},
) {
Ok(v) => {
let rv = RegistrationVerification {
key_handle: URL_SAFE_NO_PAD.encode(&v.key_handle),
pubkey: URL_SAFE_NO_PAD.encode(&v.pub_key),
device_name: v.device_name,
};
Ok(serde_json::to_string(&rv)?)
}
Err(e) => Err(e.into()),
}
}
#[derive(Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct SignatureVerification {
pub counter: u8,
}
pub fn verify_signature(
app_id: String,
challenge: String,
sign_data: String,
client_data: String,
key_handle: String,
pub_key: String,
) -> crate::Result<u32> {
let challenge_bytes = URL_SAFE_NO_PAD.decode(challenge)?;
let chal = make_challenge(&app_id, challenge_bytes);
let client_data_bytes: Vec<u8> = client_data.as_bytes().into();
let client_data_base64 = URL_SAFE_NO_PAD.encode(client_data_bytes);
let key_handle_bytes = URL_SAFE_NO_PAD.decode(&key_handle)?;
let pubkey_bytes = URL_SAFE_NO_PAD.decode(pub_key)?;
let client = U2f::new(app_id);
let mut _counter: u32 = 0;
match client.sign_response(
chal,
Registration {
// here only needs pubkey and keyhandle
key_handle: key_handle_bytes,
pub_key: pubkey_bytes,
attestation_cert: None,
device_name: None,
},
SignResponse {
// here needs client data and sig data and key_handle
signature_data: sign_data,
client_data: client_data_base64,
key_handle,
},
_counter,
) {
Ok(v) => Ok(v),
Err(e) => Err(e.into()),
}
}
@@ -1,8 +0,0 @@
Copyright (c) 2017
Licensed under either of
* Apache License, Version 2.0, (http://www.apache.org/licenses/LICENSE-2.0)
* MIT license (http://opensource.org/licenses/MIT)
at your option.
@@ -1,66 +0,0 @@
// Copyright 2021 Flavio Oliveira
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use bytes::{Buf, BufMut};
use openssl::sha::sha256;
use serde::Serialize;
use std::io::Cursor;
use crate::u2f_crate::u2ferror::U2fError;
/// The `Result` type used in this crate.
type Result<T> = ::std::result::Result<T, U2fError>;
#[derive(Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Authorization {
pub counter: u32,
pub user_presence: bool,
}
pub fn parse_sign_response(
app_id: String,
client_data: Vec<u8>,
public_key: Vec<u8>,
sign_data: Vec<u8>,
) -> Result<Authorization> {
if sign_data.len() <= 5 {
return Err(U2fError::InvalidSignatureData);
}
let user_presence_flag = &sign_data[0];
let counter = &sign_data[1..=4];
let signature = &sign_data[5..];
// Let's build the msg to verify the signature
let app_id_hash = sha256(&app_id.into_bytes());
let client_data_hash = sha256(&client_data[..]);
let mut msg = vec![];
msg.put(app_id_hash.as_ref());
msg.put_u8(*user_presence_flag);
msg.put(counter);
msg.put(client_data_hash.as_ref());
let public_key = super::crypto::NISTP256Key::from_bytes(&public_key)?;
// The signature is to be verified by the relying party using the public key obtained during registration.
let verified = public_key.verify_signature(signature, msg.as_ref())?;
if !verified {
return Err(U2fError::BadSignature);
}
let authorization = Authorization {
counter: get_counter(counter),
user_presence: true,
};
Ok(authorization)
}
fn get_counter(counter: &[u8]) -> u32 {
let mut buf = Cursor::new(counter);
buf.get_u32()
}
@@ -1,157 +0,0 @@
// Copyright 2021 Flavio Oliveira
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
//! Cryptographic operation wrapper for Webauthn. This module exists to
//! allow ease of auditing, safe operation wrappers for the webauthn library,
//! and cryptographic provider abstraction. This module currently uses OpenSSL
//! as the cryptographic primitive provider.
// Source can be found here: https://github.com/Firstyear/webauthn-rs/blob/master/src/crypto.rs
#![allow(non_camel_case_types)]
use openssl::{bn, ec, hash, nid, sign, x509};
use std::convert::TryFrom;
// use super::constants::*;
use crate::u2f_crate::u2ferror::U2fError;
use openssl::pkey::Public;
// use super::proto::*;
// Why OpenSSL over another rust crate?
// - Well, the openssl crate allows us to reconstruct a public key from the
// x/y group coords, where most others want a pkcs formatted structure. As
// a result, it's easiest to use openssl as it gives us exactly what we need
// for these operations, and despite it's many challenges as a library, it
// has resources and investment into it's maintenance, so we can a least
// assert a higher level of confidence in it that <backyard crypto here>.
// Object({Integer(-3): Bytes([48, 185, 178, 204, 113, 186, 105, 138, 190, 33, 160, 46, 131, 253, 100, 177, 91, 243, 126, 128, 245, 119, 209, 59, 186, 41, 215, 196, 24, 222, 46, 102]), Integer(-2): Bytes([158, 212, 171, 234, 165, 197, 86, 55, 141, 122, 253, 6, 92, 242, 242, 114, 158, 221, 238, 163, 127, 214, 120, 157, 145, 226, 232, 250, 144, 150, 218, 138]), Integer(-1): U64(1), Integer(1): U64(2), Integer(3): I64(-7)})
//
/// An X509PublicKey. This is what is otherwise known as a public certificate
/// which comprises a public key and other signed metadata related to the issuer
/// of the key.
pub struct X509PublicKey {
pubk: x509::X509,
}
impl std::fmt::Debug for X509PublicKey {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "X509PublicKey")
}
}
impl TryFrom<&[u8]> for X509PublicKey {
type Error = U2fError;
// Must be DER bytes. If you have PEM, base64decode first!
fn try_from(d: &[u8]) -> Result<Self, Self::Error> {
let pubk = x509::X509::from_der(d)?;
Ok(X509PublicKey { pubk })
}
}
impl X509PublicKey {
pub(crate) fn common_name(&self) -> Option<String> {
let cert = &self.pubk;
let subject = cert.subject_name();
let common = subject
.entries_by_nid(openssl::nid::Nid::COMMONNAME)
.next()
.map(|b| b.data().as_slice());
if let Some(common) = common {
std::str::from_utf8(common).ok().map(|s| s.to_string())
} else {
None
}
}
pub(crate) fn is_secp256r1(&self) -> Result<bool, U2fError> {
// Can we get the public key?
let pk = self.pubk.public_key()?;
let ec_key = pk.ec_key()?;
ec_key.check_key()?;
let ec_grpref = ec_key.group();
let ec_curve = ec_grpref.curve_name().ok_or(U2fError::OpenSSLNoCurveName)?;
Ok(ec_curve == nid::Nid::X9_62_PRIME256V1)
}
pub(crate) fn verify_signature(
&self,
signature: &[u8],
verification_data: &[u8],
) -> Result<bool, U2fError> {
let pkey = self.pubk.public_key()?;
// TODO: Should this determine the hash type from the x509 cert? Or other?
let mut verifier = sign::Verifier::new(hash::MessageDigest::sha256(), &pkey)?;
verifier.update(verification_data)?;
Ok(verifier.verify(signature)?)
}
}
pub struct NISTP256Key {
/// The key's public X coordinate.
pub x: [u8; 32],
/// The key's public Y coordinate.
pub y: [u8; 32],
}
impl NISTP256Key {
pub fn from_bytes(public_key_bytes: &[u8]) -> Result<Self, U2fError> {
if public_key_bytes.len() != 65 {
return Err(U2fError::InvalidPublicKey);
}
if public_key_bytes[0] != 0x04 {
return Err(U2fError::InvalidPublicKey);
}
let mut x: [u8; 32] = Default::default();
x.copy_from_slice(&public_key_bytes[1..=32]);
let mut y: [u8; 32] = Default::default();
y.copy_from_slice(&public_key_bytes[33..=64]);
Ok(NISTP256Key { x, y })
}
fn get_key(&self) -> Result<ec::EcKey<Public>, U2fError> {
let ec_group = ec::EcGroup::from_curve_name(openssl::nid::Nid::X9_62_PRIME256V1)?;
let xbn = bn::BigNum::from_slice(&self.x)?;
let ybn = bn::BigNum::from_slice(&self.y)?;
let ec_key = openssl::ec::EcKey::from_public_key_affine_coordinates(&ec_group, &xbn, &ybn)?;
// Validate the key is sound. IIRC this actually checks the values
// are correctly on the curve as specified
ec_key.check_key()?;
Ok(ec_key)
}
pub fn verify_signature(
&self,
signature: &[u8],
verification_data: &[u8],
) -> Result<bool, U2fError> {
let pkey = self.get_key()?;
let signature = openssl::ecdsa::EcdsaSig::from_der(signature)?;
let hash = openssl::sha::sha256(verification_data);
Ok(signature.verify(hash.as_ref(), &pkey)?)
}
}
@@ -1,55 +0,0 @@
// Copyright 2021 Flavio Oliveira
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
// As defined by FIDO U2F Javascript API.
// https://fidoalliance.org/specs/fido-u2f-v1.0-nfc-bt-amendment-20150514/fido-u2f-javascript-api.html#registration
use serde::{Deserialize, Serialize};
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct U2fRegisterRequest {
pub app_id: String,
pub register_requests: Vec<RegisterRequest>,
pub registered_keys: Vec<RegisteredKey>,
}
#[derive(Serialize)]
pub struct RegisterRequest {
pub version: String,
pub challenge: String,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RegisteredKey {
pub version: String,
pub key_handle: Option<String>,
pub app_id: String,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RegisterResponse {
pub registration_data: String,
pub version: String,
pub client_data: String,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct U2fSignRequest {
pub app_id: String,
pub challenge: String,
pub registered_keys: Vec<RegisteredKey>,
}
#[derive(Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SignResponse {
pub key_handle: String,
pub signature_data: String,
pub client_data: String,
}
@@ -1,13 +0,0 @@
// Copyright 2021 Flavio Oliveira
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
mod util;
pub mod authorization;
mod crypto;
pub mod messages;
pub mod protocol;
pub mod register;
pub mod u2ferror;
@@ -1,192 +0,0 @@
// Copyright 2021 Flavio Oliveira
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use crate::u2f_crate::authorization::*;
use crate::u2f_crate::messages::*;
use crate::u2f_crate::register::*;
use crate::u2f_crate::u2ferror::U2fError;
use crate::u2f_crate::util::*;
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
use chrono::prelude::*;
use chrono::Duration;
use serde::{Deserialize, Serialize};
type Result<T> = ::std::result::Result<T, U2fError>;
#[derive(Clone)]
pub struct U2f {
app_id: String,
}
#[derive(Deserialize, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Challenge {
pub app_id: String,
pub challenge: String,
pub timestamp: String,
}
impl Challenge {
// Not used in this plugin.
#[allow(dead_code)]
pub fn new() -> Self {
Challenge {
app_id: String::new(),
challenge: String::new(),
timestamp: String::new(),
}
}
}
impl U2f {
// The app ID is a string used to uniquely identify an U2F app
pub fn new(app_id: String) -> Self {
U2f { app_id }
}
// Not used in this plugin.
#[allow(dead_code)]
pub fn generate_challenge(&self) -> Result<Challenge> {
let utc: DateTime<Utc> = Utc::now();
let challenge_bytes = generate_challenge(32)?;
let challenge = Challenge {
challenge: URL_SAFE_NO_PAD.encode(challenge_bytes),
timestamp: format!("{:?}", utc),
app_id: self.app_id.clone(),
};
Ok(challenge.clone())
}
// Not used in this plugin.
#[allow(dead_code)]
pub fn request(
&self,
challenge: Challenge,
registrations: Vec<Registration>,
) -> Result<U2fRegisterRequest> {
let u2f_request = U2fRegisterRequest {
app_id: self.app_id.clone(),
register_requests: self.register_request(challenge),
registered_keys: self.registered_keys(registrations),
};
Ok(u2f_request)
}
fn register_request(&self, challenge: Challenge) -> Vec<RegisterRequest> {
let mut requests: Vec<RegisterRequest> = vec![];
let request = RegisterRequest {
version: U2F_V2.into(),
challenge: challenge.challenge,
};
requests.push(request);
requests
}
pub fn register_response(
&self,
challenge: Challenge,
response: RegisterResponse,
) -> Result<Registration> {
if expiration(challenge.timestamp) > Duration::seconds(300) {
return Err(U2fError::ChallengeExpired);
}
let registration_data: Vec<u8> = URL_SAFE_NO_PAD
.decode(&response.registration_data[..])
.unwrap();
let client_data: Vec<u8> = URL_SAFE_NO_PAD.decode(&response.client_data[..]).unwrap();
parse_registration(challenge.app_id, client_data, registration_data)
}
fn registered_keys(&self, registrations: Vec<Registration>) -> Vec<RegisteredKey> {
let mut keys: Vec<RegisteredKey> = vec![];
for registration in registrations {
keys.push(get_registered_key(
self.app_id.clone(),
registration.key_handle,
));
}
keys
}
// Not used in this plugin.
#[allow(dead_code)]
pub fn sign_request(
&self,
challenge: Challenge,
registrations: Vec<Registration>,
) -> U2fSignRequest {
let mut keys: Vec<RegisteredKey> = vec![];
for registration in registrations {
keys.push(get_registered_key(
self.app_id.clone(),
registration.key_handle,
));
}
let signed_request = U2fSignRequest {
app_id: self.app_id.clone(),
challenge: URL_SAFE_NO_PAD.encode(challenge.challenge.as_bytes()),
registered_keys: keys,
};
signed_request
}
pub fn sign_response(
&self,
challenge: Challenge,
reg: Registration,
sign_resp: SignResponse,
counter: u32,
) -> Result<u32> {
if expiration(challenge.timestamp) > Duration::seconds(300) {
return Err(U2fError::ChallengeExpired);
}
if sign_resp.key_handle != get_encoded(&reg.key_handle[..]) {
return Err(U2fError::WrongKeyHandler);
}
let client_data: Vec<u8> = URL_SAFE_NO_PAD
.decode(&sign_resp.client_data[..])
.map_err(|_e| U2fError::InvalidClientData)?;
let sign_data: Vec<u8> = URL_SAFE_NO_PAD
.decode(&sign_resp.signature_data[..])
.map_err(|_e| U2fError::InvalidSignatureData)?;
let public_key = reg.pub_key;
let auth = parse_sign_response(
self.app_id.clone(),
client_data.clone(),
public_key,
sign_data.clone(),
);
match auth {
Ok(ref res) => {
// CounterTooLow is raised when the counter value received from the device is
// lower than last stored counter value.
if res.counter < counter {
Err(U2fError::CounterTooLow)
} else {
Ok(res.counter)
}
}
Err(e) => Err(e),
}
}
}
@@ -1,102 +0,0 @@
// Copyright 2021 Flavio Oliveira
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use byteorder::{BigEndian, ByteOrder};
use bytes::{BufMut, Bytes};
use openssl::sha::sha256;
use serde::Serialize;
use crate::u2f_crate::messages::RegisteredKey;
use crate::u2f_crate::u2ferror::U2fError;
use crate::u2f_crate::util::*;
use std::convert::TryFrom;
/// The `Result` type used in this crate.
type Result<T> = ::std::result::Result<T, U2fError>;
// Single enrolment or pairing between an application and a token.
#[derive(Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Registration {
pub key_handle: Vec<u8>,
pub pub_key: Vec<u8>,
// AttestationCert can be null for Authenticate requests.
pub attestation_cert: Option<Vec<u8>>,
pub device_name: Option<String>,
}
pub fn parse_registration(
app_id: String,
client_data: Vec<u8>,
registration_data: Vec<u8>,
) -> Result<Registration> {
let reserved_byte = registration_data[0];
if reserved_byte != 0x05 {
return Err(U2fError::InvalidReservedByte);
}
let mut mem = Bytes::from(registration_data);
//Start parsing ... advance the reserved byte.
let _ = mem.split_to(1);
// P-256 NIST elliptic curve
let public_key = mem.split_to(65);
// Key Handle
let key_handle_size = mem.split_to(1);
let key_len = BigEndian::read_uint(&key_handle_size[..], 1);
let key_handle = mem.split_to(key_len as usize);
// The certificate length needs to be inferred by parsing.
let cert_len = asn_length(mem.clone()).unwrap();
let attestation_certificate = mem.split_to(cert_len);
// Remaining data corresponds to the signature
let signature = mem;
// Let's build the msg to verify the signature
let app_id_hash = sha256(&app_id.into_bytes());
let client_data_hash = sha256(&client_data[..]);
let mut msg = vec![0x00]; // A byte reserved for future use [1 byte] with the value 0x00
msg.put(app_id_hash.as_ref());
msg.put(client_data_hash.as_ref());
msg.put(key_handle.clone());
msg.put(public_key.clone());
// The signature is to be verified by the relying party using the public key certified
// in the attestation certificate.
let cerificate_public_key =
super::crypto::X509PublicKey::try_from(&attestation_certificate[..])?;
if !(cerificate_public_key.is_secp256r1()?) {
return Err(U2fError::BadCertificate);
}
let verified = cerificate_public_key.verify_signature(&signature[..], &msg[..])?;
if !verified {
return Err(U2fError::BadCertificate);
}
let registration = Registration {
key_handle: key_handle[..].to_vec(),
pub_key: public_key[..].to_vec(),
attestation_cert: Some(attestation_certificate[..].to_vec()),
device_name: cerificate_public_key.common_name(),
};
Ok(registration)
}
pub fn get_registered_key(app_id: String, key_handle: Vec<u8>) -> RegisteredKey {
RegisteredKey {
app_id,
version: U2F_V2.into(),
key_handle: Some(get_encoded(key_handle.as_slice())),
}
}
@@ -1,40 +0,0 @@
// Copyright 2021 Flavio Oliveira
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use thiserror::Error;
#[derive(Debug, Error)]
pub enum U2fError {
#[error("ASM1 Decoder error")]
Asm1DecoderError,
#[error("Not able to verify signature")]
BadSignature,
#[error("Not able to generate random bytes")]
RandomSecureBytesError,
#[error("Invalid Reserved Byte")]
InvalidReservedByte,
#[error("Challenge Expired")]
ChallengeExpired,
#[error("Wrong Key Handler")]
WrongKeyHandler,
#[error("Invalid Client Data")]
InvalidClientData,
#[error("Invalid Signature Data")]
InvalidSignatureData,
#[error("Invalid User Presence Byte")]
InvalidUserPresenceByte,
#[error("Failed to parse certificate")]
BadCertificate,
#[error("Not Trusted Anchor")]
NotTrustedAnchor,
#[error("Counter too low")]
CounterTooLow,
#[error("Invalid public key")]
OpenSSLNoCurveName,
#[error("OpenSSL no curve name")]
InvalidPublicKey,
#[error(transparent)]
OpenSSLError(#[from] openssl::error::ErrorStack),
}
@@ -1,67 +0,0 @@
// Copyright 2021 Flavio Oliveira
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use crate::u2f_crate::u2ferror::U2fError;
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
use bytes::Bytes;
use chrono::prelude::*;
use chrono::Duration;
use openssl::rand;
/// The `Result` type used in this crate.
type Result<T> = ::std::result::Result<T, U2fError>;
pub const U2F_V2: &str = "U2F_V2";
// Generates a challenge from a secure, random source.
pub fn generate_challenge(size: usize) -> Result<Vec<u8>> {
let mut bytes: Vec<u8> = vec![0; size];
rand::rand_bytes(&mut bytes).map_err(|_e| U2fError::RandomSecureBytesError)?;
Ok(bytes)
}
pub fn expiration(timestamp: String) -> Duration {
let now: DateTime<Utc> = Utc::now();
let ts = timestamp.parse::<DateTime<Utc>>();
now.signed_duration_since(ts.unwrap())
}
// Decode initial bytes of buffer as ASN and return the length of the encoded structure.
// http://en.wikipedia.org/wiki/X.690
pub fn asn_length(mem: Bytes) -> Result<usize> {
let buffer: &[u8] = &mem[..];
if mem.len() < 2 || buffer[0] != 0x30 {
// Type
return Err(U2fError::Asm1DecoderError);
}
let len = buffer[1]; // Len
if len & 0x80 == 0 {
return Ok((len & 0x7f) as usize);
}
let numbem_of_bytes = len & 0x7f;
if numbem_of_bytes == 0 {
return Err(U2fError::Asm1DecoderError);
}
let mut length: usize = 0;
for num in 0..numbem_of_bytes {
length = length * 0x100 + (buffer[(2 + num) as usize] as usize);
}
length += numbem_of_bytes as usize;
Ok(length + 2) // Add the 2 initial bytes: type and length.
}
pub fn get_encoded(data: &[u8]) -> String {
let encoded: String = URL_SAFE_NO_PAD.encode(data);
encoded.trim_end_matches('=').to_string()
}
-1
View File
@@ -1 +0,0 @@
node_modules
+55 -1
View File
@@ -1,5 +1,58 @@
# Changelog
## \[2.0.1]
- [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7.
## \[2.0.0]
- [`e2c4dfb6`](https://github.com/tauri-apps/plugins-workspace/commit/e2c4dfb6af43e5dd8d9ceba232c315f5febd55c1) Update to tauri v2 stable release.
## \[2.0.0-rc.1]
- [`e2e97db5`](https://github.com/tauri-apps/plugins-workspace/commit/e2e97db51983267f5be84d4f6f0278d58834d1f5) ([#1701](https://github.com/tauri-apps/plugins-workspace/pull/1701) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Update to tauri 2.0.0-rc.8
## \[2.0.0-rc.0]
- [`9887d1`](https://github.com/tauri-apps/plugins-workspace/commit/9887d14bd0e971c4c0f5c1188fc4005d3fc2e29e) Update to tauri RC.
## \[2.0.0-beta.8]
- [`99d6ac0f`](https://github.com/tauri-apps/plugins-workspace/commit/99d6ac0f9506a6a4a1aa59c728157190a7441af6) ([#1606](https://github.com/tauri-apps/plugins-workspace/pull/1606) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) The JS packages now specify the *minimum* `@tauri-apps/api` version instead of a single exact version.
- [`6de87966`](https://github.com/tauri-apps/plugins-workspace/commit/6de87966ecc00ad9d91c25be452f1f46bd2b7e1f) ([#1597](https://github.com/tauri-apps/plugins-workspace/pull/1597) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Update to tauri beta.25.
## \[2.0.0-beta.7]
- [`22a17980`](https://github.com/tauri-apps/plugins-workspace/commit/22a17980ff4f6f8c40adb1b8f4ffc6dae2fe7e30) ([#1537](https://github.com/tauri-apps/plugins-workspace/pull/1537) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Update to tauri beta.24.
## \[2.0.0-beta.6]
- [`76daee7a`](https://github.com/tauri-apps/plugins-workspace/commit/76daee7aafece34de3092c86e531cf9eb1138989) ([#1512](https://github.com/tauri-apps/plugins-workspace/pull/1512) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Update to tauri beta.23.
## \[2.0.0-beta.5]
- [`9013854f`](https://github.com/tauri-apps/plugins-workspace/commit/9013854f42a49a230b9dbb9d02774765528a923f)([#1382](https://github.com/tauri-apps/plugins-workspace/pull/1382)) Update to tauri beta.22.
## \[2.0.0-beta.4]
- [`430bd6f4`](https://github.com/tauri-apps/plugins-workspace/commit/430bd6f4f379bee5d232ae6b098ae131db7f178a)([#1363](https://github.com/tauri-apps/plugins-workspace/pull/1363)) Update to tauri beta.20.
## \[2.0.0-beta.3]
- [`bd1ed590`](https://github.com/tauri-apps/plugins-workspace/commit/bd1ed5903ffcce5500310dac1e59e8c67674ef1e)([#1237](https://github.com/tauri-apps/plugins-workspace/pull/1237)) Update to tauri beta.17.
## \[2.0.0-beta.4]
- [`a233919`](https://github.com/tauri-apps/plugins-workspace/commit/a2339195aa940bff86d76375fd05087595bf06ce)([#1118](https://github.com/tauri-apps/plugins-workspace/pull/1118)) Fix LaunchAgent-based autostart for macOS.
## \[2.0.0-beta.3]
- [`a04ea2f`](https://github.com/tauri-apps/plugins-workspace/commit/a04ea2f38294d5a3987578283badc8eec87a7752)([#1071](https://github.com/tauri-apps/plugins-workspace/pull/1071)) The global API script is now only added to the binary when the `withGlobalTauri` config is true.
## \[2.0.0-beta.2]
- [`99bea25`](https://github.com/tauri-apps/plugins-workspace/commit/99bea2559c2c0648c2519c50a18cd124dacef57b)([#1005](https://github.com/tauri-apps/plugins-workspace/pull/1005)) Update to tauri beta.8.
## \[2.0.0-beta.1]
- [`569defb`](https://github.com/tauri-apps/plugins-workspace/commit/569defbe9492e38938554bb7bdc1be9151456d21) Update to tauri beta.4.
@@ -41,4 +94,5 @@
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
ae67\`]\(https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
+12 -4
View File
@@ -1,19 +1,27 @@
[package]
name = "tauri-plugin-autostart"
version = "2.0.0-beta.1"
version = "2.0.1"
description = "Automatically launch your application at startup."
authors = { workspace = true }
license = { workspace = true }
edition = { workspace = true }
rust-version = { workspace = true }
repository = { workspace = true }
links = "tauri-plugin-autostart"
[package.metadata.docs.rs]
rustc-args = [ "--cfg", "docsrs" ]
rustdoc-args = [ "--cfg", "docsrs" ]
rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs"]
[package.metadata.platforms.support]
windows = { level = "full", notes = "" }
linux = { level = "full", notes = "" }
macos = { level = "full", notes = "" }
android = { level = "none", notes = "" }
ios = { level = "none", notes = "" }
[build-dependencies]
tauri-plugin = { workspace = true, features = [ "build" ] }
tauri-plugin = { workspace = true, features = ["build"] }
[dependencies]
serde = { workspace = true }
+15 -7
View File
@@ -1,10 +1,18 @@
![plugin-autostart](https://github.com/tauri-apps/plugins-workspace/raw/v2/plugins/autostart/banner.png)
Automatically launch your application at startup. Supports Windows, Mac (via AppleScript or Launch Agent), and Linux.
Automatically launch your application at startup.
| Platform | Supported |
| -------- | --------- |
| Linux | ✓ |
| Windows | ✓ |
| macOS | ✓ |
| Android | x |
| iOS | x |
## Install
_This plugin requires a Rust version of at least **1.75**_
_This plugin requires a Rust version of at least **1.77.2**_
There are three general methods of installation that we can recommend.
@@ -18,7 +26,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml
[dependencies]
tauri-plugin-autostart = "2.0.0-beta"
tauri-plugin-autostart = "2.0.0"
# alternatively with Git:
tauri-plugin-autostart = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
```
@@ -62,13 +70,13 @@ fn main() {
Afterwards all the plugin's APIs are available through the JavaScript guest bindings:
```javascript
import { enable, isEnabled, disable } from "@tauri-apps/plugin-autostart";
import { enable, isEnabled, disable } from '@tauri-apps/plugin-autostart'
await enable();
await enable()
console.log(`registered for autostart? ${await isEnabled()}`);
console.log(`registered for autostart? ${await isEnabled()}`)
disable();
disable()
```
## Contributing
+23
View File
@@ -0,0 +1,23 @@
# Security Policy
**Do not report security vulnerabilities through public GitHub issues.**
**Please use the [Private Vulnerability Disclosure](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability) feature of GitHub.**
Include as much of the following information:
- Type of issue (e.g. improper input parsing, privilege escalation, etc.)
- The location of the affected source code (tag/branch/commit or direct URL)
- Any special configuration required to reproduce the issue
- The distribution affected or used to help us with reproduction of the issue
- Step-by-step instructions to reproduce the issue
- Ideally a reproduction repository
- Impact of the issue, including how an attacker might exploit the issue
We prefer to receive reports in English.
## Contact
Please disclose a vulnerability or security relevant issue here: [https://github.com/tauri-apps/plugins-workspace/security/advisories/new](https://github.com/tauri-apps/plugins-workspace/security/advisories/new).
Alternatively, you can also contact us by email via [security@tauri.app](mailto:security@tauri.app).
+3 -1
View File
@@ -5,5 +5,7 @@
const COMMANDS: &[&str] = &["enable", "disable", "is_enabled"];
fn main() {
tauri_plugin::Builder::new(COMMANDS).build();
tauri_plugin::Builder::new(COMMANDS)
.global_api_script_path("./api-iife.js")
.build();
}
+4 -4
View File
@@ -2,16 +2,16 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
import { invoke } from "@tauri-apps/api/core";
import { invoke } from '@tauri-apps/api/core'
export async function isEnabled(): Promise<boolean> {
return await invoke("plugin:autostart|is_enabled");
return await invoke('plugin:autostart|is_enabled')
}
export async function enable(): Promise<void> {
await invoke("plugin:autostart|enable");
await invoke('plugin:autostart|enable')
}
export async function disable(): Promise<void> {
await invoke("plugin:autostart|disable");
await invoke('plugin:autostart|disable')
}
+4 -3
View File
@@ -1,10 +1,11 @@
{
"name": "@tauri-apps/plugin-autostart",
"version": "2.0.0-beta.1",
"license": "MIT or APACHE-2.0",
"version": "2.0.0",
"license": "MIT OR Apache-2.0",
"authors": [
"Tauri Programme within The Commons Conservancy"
],
"repository": "https://github.com/tauri-apps/plugins-workspace",
"type": "module",
"types": "./dist-js/index.d.ts",
"main": "./dist-js/index.cjs",
@@ -23,6 +24,6 @@
"LICENSE"
],
"dependencies": {
"@tauri-apps/api": "2.0.0-beta.2"
"@tauri-apps/api": "^2.0.0"
}
}
@@ -1,26 +1,104 @@
# Permissions
## Default Permission
## allow-disable
This permission set configures if your
application can enable or disable auto
starting the application on boot.
#### Granted Permissions
It allows all to check, enable and
disable the automatic start on boot.
- `allow-enable`
- `allow-disable`
- `allow-is-enabled`
## Permission Table
<table>
<tr>
<th>Identifier</th>
<th>Description</th>
</tr>
<tr>
<td>
`autostart:allow-disable`
</td>
<td>
Enables the disable command without any pre-configured scope.
## deny-disable
</td>
</tr>
<tr>
<td>
`autostart:deny-disable`
</td>
<td>
Denies the disable command without any pre-configured scope.
## allow-enable
</td>
</tr>
<tr>
<td>
`autostart:allow-enable`
</td>
<td>
Enables the enable command without any pre-configured scope.
## deny-enable
</td>
</tr>
<tr>
<td>
`autostart:deny-enable`
</td>
<td>
Denies the enable command without any pre-configured scope.
## allow-is-enabled
</td>
</tr>
<tr>
<td>
`autostart:allow-is-enabled`
</td>
<td>
Enables the is_enabled command without any pre-configured scope.
## deny-is-enabled
</td>
</tr>
<tr>
<td>
`autostart:deny-is-enabled`
</td>
<td>
Denies the is_enabled command without any pre-configured scope.
</td>
</tr>
</table>
@@ -0,0 +1,15 @@
"$schema" = "schemas/schema.json"
[default]
description = """
This permission set configures if your
application can enable or disable auto
starting the application on boot.
#### Granted Permissions
It allows all to check, enable and
disable the automatic start on boot.
"""
permissions = ["allow-enable", "allow-disable", "allow-is-enabled"]
@@ -49,7 +49,7 @@
"minimum": 1.0
},
"description": {
"description": "Human-readable description of what the permission does.",
"description": "Human-readable description of what the permission does. Tauri convention is to use <h4> headings in markdown content for Tauri documentation generation purposes.",
"type": [
"string",
"null"
@@ -111,7 +111,7 @@
"type": "string"
},
"description": {
"description": "Human-readable description of what the permission does.",
"description": "Human-readable description of what the permission does. Tauri internal convention is to use <h4> headings in markdown content for Tauri documentation generation purposes.",
"type": [
"string",
"null"
@@ -136,6 +136,16 @@
"$ref": "#/definitions/Scopes"
}
]
},
"platforms": {
"description": "Target platforms this permission applies. By default all platforms are affected by this permission.",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/Target"
}
}
}
},
@@ -162,7 +172,7 @@
}
},
"Scopes": {
"description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.",
"description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command. The configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json { \"allow\": [{ \"path\": \"$HOME/**\" }], \"deny\": [{ \"path\": \"$HOME/secret.txt\" }] } ```",
"type": "object",
"properties": {
"allow": {
@@ -176,7 +186,7 @@
}
},
"deny": {
"description": "Data that defines what is denied by the scope.",
"description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.",
"type": [
"array",
"null"
@@ -241,50 +251,83 @@
}
]
},
"Target": {
"description": "Platform target.",
"oneOf": [
{
"description": "MacOS.",
"type": "string",
"enum": [
"macOS"
]
},
{
"description": "Windows.",
"type": "string",
"enum": [
"windows"
]
},
{
"description": "Linux.",
"type": "string",
"enum": [
"linux"
]
},
{
"description": "Android.",
"type": "string",
"enum": [
"android"
]
},
{
"description": "iOS.",
"type": "string",
"enum": [
"iOS"
]
}
]
},
"PermissionKind": {
"type": "string",
"oneOf": [
{
"description": "allow-disable -> Enables the disable command without any pre-configured scope.",
"description": "Enables the disable command without any pre-configured scope.",
"type": "string",
"enum": [
"allow-disable"
]
"const": "allow-disable"
},
{
"description": "deny-disable -> Denies the disable command without any pre-configured scope.",
"description": "Denies the disable command without any pre-configured scope.",
"type": "string",
"enum": [
"deny-disable"
]
"const": "deny-disable"
},
{
"description": "allow-enable -> Enables the enable command without any pre-configured scope.",
"description": "Enables the enable command without any pre-configured scope.",
"type": "string",
"enum": [
"allow-enable"
]
"const": "allow-enable"
},
{
"description": "deny-enable -> Denies the enable command without any pre-configured scope.",
"description": "Denies the enable command without any pre-configured scope.",
"type": "string",
"enum": [
"deny-enable"
]
"const": "deny-enable"
},
{
"description": "allow-is-enabled -> Enables the is_enabled command without any pre-configured scope.",
"description": "Enables the is_enabled command without any pre-configured scope.",
"type": "string",
"enum": [
"allow-is-enabled"
]
"const": "allow-is-enabled"
},
{
"description": "deny-is-enabled -> Denies the is_enabled command without any pre-configured scope.",
"description": "Denies the is_enabled command without any pre-configured scope.",
"type": "string",
"enum": [
"deny-is-enabled"
]
"const": "deny-is-enabled"
},
{
"description": "This permission set configures if your\napplication can enable or disable auto\nstarting the application on boot.\n\n#### Granted Permissions\n\nIt allows all to check, enable and\ndisable the automatic start on boot.\n\n",
"type": "string",
"const": "default"
}
]
}
+2 -2
View File
@@ -2,6 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
import { createConfig } from "../../shared/rollup.config.js";
import { createConfig } from '../../shared/rollup.config.js'
export default createConfig();
export default createConfig()
+6 -6
View File
@@ -107,7 +107,6 @@ pub fn init<R: Runtime>(
args: Option<Vec<&'static str>>,
) -> TauriPlugin<R> {
Builder::new("autostart")
.js_init_script(include_str!("api-iife.js").to_string())
.invoke_handler(tauri::generate_handler![enable, disable, is_enabled])
.setup(move |app, _api| {
let mut builder = AutoLaunchBuilder::new();
@@ -130,11 +129,12 @@ pub fn init<R: Runtime>(
// exe path to not break it.
let exe_path = current_exe.canonicalize()?.display().to_string();
let parts: Vec<&str> = exe_path.split(".app/").collect();
let app_path = if parts.len() == 2 {
format!("{}.app", parts.first().unwrap())
} else {
exe_path
};
let app_path =
if parts.len() == 2 && matches!(macos_launcher, MacosLauncher::AppleScript) {
format!("{}.app", parts.first().unwrap())
} else {
exe_path
};
info!("auto_start path {}", &app_path);
builder.set_app_path(&app_path);
}
+81 -1
View File
@@ -1,5 +1,80 @@
# Changelog
## \[2.0.1]
- [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7.
## \[2.0.0]
- [`e2c4dfb6`](https://github.com/tauri-apps/plugins-workspace/commit/e2c4dfb6af43e5dd8d9ceba232c315f5febd55c1) Update to tauri v2 stable release.
## \[2.0.0-rc.2]
- [`79d6e19c`](https://github.com/tauri-apps/plugins-workspace/commit/79d6e19c4b38bae0cab29eb88df379e2237d9aac) ([#1777](https://github.com/tauri-apps/plugins-workspace/pull/1777)) Fixed an issue which caused checkPermission and requestPermission to be mixed up.
## \[2.0.0-rc.4]
- [`713c54ef`](https://github.com/tauri-apps/plugins-workspace/commit/713c54ef8365d36afd84585dcabed2fbb751223d) ([#1749](https://github.com/tauri-apps/plugins-workspace/pull/1749) by [@olivierlemasle](https://github.com/tauri-apps/plugins-workspace/../../olivierlemasle)) Remove unused Android dependencies.
- [`8c3a6a25`](https://github.com/tauri-apps/plugins-workspace/commit/8c3a6a253d7029d370659d2102f91a458745d345) ([#1758](https://github.com/tauri-apps/plugins-workspace/pull/1758) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Validate missing `NSCameraUsageDescription` Info.plist value.
## \[2.0.0-rc.1]
- [`e2e97db5`](https://github.com/tauri-apps/plugins-workspace/commit/e2e97db51983267f5be84d4f6f0278d58834d1f5) ([#1701](https://github.com/tauri-apps/plugins-workspace/pull/1701) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Use `PermissionState` from the `tauri` crate, which now also includes a "prompt with rationale" variant for Android (returned when your app must explain to the user why it needs the permission).
- [`e2e97db5`](https://github.com/tauri-apps/plugins-workspace/commit/e2e97db51983267f5be84d4f6f0278d58834d1f5) ([#1701](https://github.com/tauri-apps/plugins-workspace/pull/1701) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Update to tauri 2.0.0-rc.8
## \[2.0.0-rc.2]
- [`b9147758`](https://github.com/tauri-apps/plugins-workspace/commit/b914775898c2bee7ceb20bd17ee595005cd17a64) ([#1679](https://github.com/tauri-apps/plugins-workspace/pull/1679) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Explicitly set a minimum macOS version for the Swift package.
## \[2.0.0-rc.1]
- [`2c00c029`](https://github.com/tauri-apps/plugins-workspace/commit/2c00c0292c9127b81567de46691e8c0f73557261) ([#1630](https://github.com/tauri-apps/plugins-workspace/pull/1630) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Fixed an issue that caused multi-word IIFE names to not be formatted correctly. For example the `barcode-scanner` was defined as `window.__TAURI_PLUGIN_CLIPBOARDMANAGER__` instead of `window.__TAURI_PLUGIN_CLIPBOARD_MANAGER__`.
### changes
- [`6b079cfd`](https://github.com/tauri-apps/plugins-workspace/commit/6b079cfdd107c94abc2c7300f6af00bac3ff4040) ([#1649](https://github.com/tauri-apps/plugins-workspace/pull/1649) by [@ahqsoftwares](https://github.com/tauri-apps/plugins-workspace/../../ahqsoftwares)) Remove targetSdk from build.kts files as it is deprecated and will be removed from DSL v9.0
## \[2.0.0-rc.0]
- [`9887d1`](https://github.com/tauri-apps/plugins-workspace/commit/9887d14bd0e971c4c0f5c1188fc4005d3fc2e29e) Update to tauri RC.
## \[2.0.0-beta.8]
- [`99d6ac0f`](https://github.com/tauri-apps/plugins-workspace/commit/99d6ac0f9506a6a4a1aa59c728157190a7441af6) ([#1606](https://github.com/tauri-apps/plugins-workspace/pull/1606) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) The JS packages now specify the *minimum* `@tauri-apps/api` version instead of a single exact version.
- [`6de87966`](https://github.com/tauri-apps/plugins-workspace/commit/6de87966ecc00ad9d91c25be452f1f46bd2b7e1f) ([#1597](https://github.com/tauri-apps/plugins-workspace/pull/1597) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Update to tauri beta.25.
## \[2.0.0-beta.7]
- [`22a17980`](https://github.com/tauri-apps/plugins-workspace/commit/22a17980ff4f6f8c40adb1b8f4ffc6dae2fe7e30) ([#1537](https://github.com/tauri-apps/plugins-workspace/pull/1537) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Update to tauri beta.24.
## \[2.0.0-beta.6]
- [`76daee7a`](https://github.com/tauri-apps/plugins-workspace/commit/76daee7aafece34de3092c86e531cf9eb1138989) ([#1512](https://github.com/tauri-apps/plugins-workspace/pull/1512) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Update to tauri beta.23.
## \[2.0.0-beta.5]
- [`9013854f`](https://github.com/tauri-apps/plugins-workspace/commit/9013854f42a49a230b9dbb9d02774765528a923f)([#1382](https://github.com/tauri-apps/plugins-workspace/pull/1382)) Update to tauri beta.22.
## \[2.0.0-beta.4]
- [`430bd6f4`](https://github.com/tauri-apps/plugins-workspace/commit/430bd6f4f379bee5d232ae6b098ae131db7f178a)([#1363](https://github.com/tauri-apps/plugins-workspace/pull/1363)) Update to tauri beta.20.
## \[2.0.0-beta.3]
- [`bd1ed590`](https://github.com/tauri-apps/plugins-workspace/commit/bd1ed5903ffcce5500310dac1e59e8c67674ef1e)([#1237](https://github.com/tauri-apps/plugins-workspace/pull/1237)) Update to tauri beta.17.
## \[2.0.0-beta.4]
- [`326df688`](https://github.com/tauri-apps/plugins-workspace/commit/326df6883998d416fc0837583ed972854628bb52)([#1236](https://github.com/tauri-apps/plugins-workspace/pull/1236)) Fixes command argument parsing on iOS.
## \[2.0.0-beta.3]
- [`a04ea2f`](https://github.com/tauri-apps/plugins-workspace/commit/a04ea2f38294d5a3987578283badc8eec87a7752)([#1071](https://github.com/tauri-apps/plugins-workspace/pull/1071)) The global API script is now only added to the binary when the `withGlobalTauri` config is true.
## \[2.0.0-beta.2]
- [`99bea25`](https://github.com/tauri-apps/plugins-workspace/commit/99bea2559c2c0648c2519c50a18cd124dacef57b)([#1005](https://github.com/tauri-apps/plugins-workspace/pull/1005)) Update to tauri beta.8.
## \[2.0.0-beta.1]
- [`569defb`](https://github.com/tauri-apps/plugins-workspace/commit/569defbe9492e38938554bb7bdc1be9151456d21) Update to tauri beta.4.
@@ -28,4 +103,9 @@
## \[2.0.0-alpha.0]
- [`454428c`](https://github.com/tauri-apps/plugins-workspace/commit/454428cd50ce4962f0bad8e355aebc68af8cc61f)([#536](https://github.com/tauri-apps/plugins-workspace/pull/536)) Initial release.
commit/454428cd50ce4962f0bad8e355aebc68af8cc61f)([#536](https://github.com/tauri-apps/plugins-workspace/pull/536)) Initial release.
commit/454428cd50ce4962f0bad8e355aebc68af8cc61f)([#536](https://github.com/tauri-apps/plugins-workspace/pull/536)) Initial release.
36]\(https://github.com/tauri-apps/plugins-workspace/pull/536)) Initial release.
commit/454428cd50ce4962f0bad8e355aebc68af8cc61f)([#536](https://github.com/tauri-apps/plugins-workspace/pull/536)) Initial release.
.
commit/454428cd50ce4962f0bad8e355aebc68af8cc61f)([#536](https://github.com/tauri-apps/plugins-workspace/pull/536)) Initial release.
github.com/tauri-apps/plugins-workspace/pull/536)) Initial release.
+17 -5
View File
@@ -1,20 +1,29 @@
[package]
name = "tauri-plugin-barcode-scanner"
version = "2.0.0-beta.1"
version = "2.0.1"
description = "Scan QR codes, EAN-13 and other kinds of barcodes on Android and iOS"
edition = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
rust-version = { workspace = true }
repository = { workspace = true }
links = "tauri-plugin-barcode-scanner"
[package.metadata.docs.rs]
rustc-args = [ "--cfg", "docsrs" ]
rustdoc-args = [ "--cfg", "docsrs" ]
targets = [ "x86_64-linux-android" ]
rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs"]
targets = ["x86_64-linux-android"]
[package.metadata.platforms.support]
windows = { level = "none", notes = "" }
linux = { level = "none", notes = "" }
macos = { level = "none", notes = "" }
android = { level = "full", notes = "" }
ios = { level = "full", notes = "" }
[build-dependencies]
tauri-plugin = { workspace = true, features = [ "build" ] }
tauri-plugin = { workspace = true, features = ["build"] }
[dependencies]
serde = { workspace = true }
@@ -22,3 +31,6 @@ serde_json = { workspace = true }
tauri = { workspace = true }
log = { workspace = true }
thiserror = { workspace = true }
[target.'cfg(target_os = "ios")'.dependencies]
tauri = { workspace = true, features = ["wry"] }
+12 -4
View File
@@ -1,7 +1,15 @@
![Barcode Scanner](https://github.com/tauri-apps/plugins-workspace/raw/v2/plugins/scanner/banner.png)
![Barcode Scanner](https://github.com/tauri-apps/plugins-workspace/raw/v2/plugins/barcode-scanner/banner.png)
Allows your mobile application to use the camera to scan QR codes, EAN-13 and other kinds of barcodes.
| Platform | Supported |
| -------- | --------- |
| Linux | x |
| Windows | x |
| macOS | x |
| Android | ✓ |
| iOS | ✓ |
## Install
_This plugin requires a Rust version of at least **1.64**_
@@ -18,7 +26,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml
[dependencies]
tauri-plugin-barcode-scanner = "2.0.0-beta"
tauri-plugin-barcode-scanner = "2.0.0"
# alternatively with Git:
tauri-plugin-barcode-scanner = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
```
@@ -60,12 +68,12 @@ fn main() {
Afterwards all the plugin's APIs are available through the JavaScript guest bindings:
```javascript
import { scan } from "@tauri-apps/plugin-barcode-scanner";
import { scan } from '@tauri-apps/plugin-barcode-scanner'
// `windowed: true` actually sets the webview to transparent
// instead of opening a separate view for the camera
// make sure your user interface is ready to show what is underneath with a transparent element
scan({ windowed: true, formats: [""] })
scan({ windowed: true, formats: [''] })
```
## Contributing
-1
View File
@@ -54,7 +54,6 @@ The camera has two modes. The first one is where the user can see the background
The second mode allows the developer to assist the user and add a transparent overlay to the image, providing hints or additional information (like a link preview).
The overlay could be made non-transparent by the application frontend and as long as the app is open (and in some cases) it could read QR codes in range of the camera lense.
#### Out Of Scope
- Exploits in the operating system QR code parsing functionality
@@ -5,11 +5,10 @@ plugins {
android {
namespace = "app.tauri.barcodescanner"
compileSdk = 32
compileSdk = 34
defaultConfig {
minSdk = 24
targetSdk = 32
minSdk = 24
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
@@ -48,9 +47,5 @@ dependencies {
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
implementation("com.journeyapps:zxing-android-embedded:4.3.0") {
isTransitive = false
}
implementation("com.google.zxing:core:3.3.0")
implementation(project(":tauri-android"))
}
@@ -2,10 +2,8 @@
xmlns:tools="http://schemas.android.com/tools"
android:hardwareAccelerated="true">
<!-- Paste the following line into the AndroidManifest.xml of your project -->
<!-- See also: https://capacitorjs.com/docs/plugins/android#manifest -->
<!-- <uses-feature android:name="android.hardware.camera" android:required="false" /> -->
<uses-sdk tools:overrideLibrary="com.google.zxing.client.android" />
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-feature android:name="android.hardware.camera.any"/>
</manifest>
@@ -42,7 +42,6 @@ import app.tauri.annotation.Permission
import app.tauri.annotation.PermissionCallback
import app.tauri.annotation.TauriPlugin
import app.tauri.plugin.Invoke
import app.tauri.plugin.JSArray
import app.tauri.plugin.JSObject
import app.tauri.plugin.Plugin
import com.google.common.util.concurrent.ListenableFuture
@@ -50,7 +49,6 @@ import com.google.mlkit.vision.barcode.BarcodeScannerOptions
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.barcode.common.Barcode
import com.google.mlkit.vision.common.InputImage
import org.json.JSONException
import java.util.Collections
import java.util.concurrent.ExecutionException
@@ -91,22 +91,10 @@ class GraphicOverlay: View {
return
}
val zLowerBoundInScreenPixel: Float
val zUpperBoundInScreenPixel: Float
if (rescaleZForVisualization) {
zLowerBoundInScreenPixel = (-0.001f).coerceAtMost(scale(zMin))
zUpperBoundInScreenPixel = 0.001f.coerceAtLeast(scale(zMax))
} else {
val defaultRangeFactor = 1f
zLowerBoundInScreenPixel = -defaultRangeFactor * canvas.width
zUpperBoundInScreenPixel = defaultRangeFactor * canvas.width
}
val zInScreenPixel = scale(zInImagePixel)
if (zInScreenPixel < 0) {
val v = (zInScreenPixel / zLowerBoundInScreenPixel * 255).toInt()
paint.setARGB(0, 0, 255, 0)
} else {
val v = (zInScreenPixel / zUpperBoundInScreenPixel * 255).toInt()
paint.setARGB(0, 0, 255, 0)
}
}
@@ -180,7 +168,7 @@ class GraphicOverlay: View {
needUpdateTransformation = false
}
override fun onDraw(canvas: Canvas?) {
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
synchronized(lock) {
updateTransformationIfNeeded()
+1
View File
@@ -0,0 +1 @@
if("__TAURI__"in window){var __TAURI_PLUGIN_BARCODE_SCANNER__=function(n){"use strict";async function e(n,e={},r){return window.__TAURI_INTERNALS__.invoke(n,e,r)}var r;return"function"==typeof SuppressedError&&SuppressedError,n.Format=void 0,(r=n.Format||(n.Format={})).QRCode="QR_CODE",r.UPC_A="UPC_A",r.UPC_E="UPC_E",r.EAN8="EAN_8",r.EAN13="EAN_13",r.Code39="CODE_39",r.Code93="CODE_93",r.Code128="CODE_128",r.Codabar="CODABAR",r.ITF="ITF",r.Aztec="AZTEC",r.DataMatrix="DATA_MATRIX",r.PDF417="PDF_417",n.cancel=async function(){await e("plugin:barcode-scanner|cancel")},n.checkPermissions=async function(){return await async function(n){return e(`plugin:${n}|check_permissions`)}("barcode-scanner").then((n=>n.camera))},n.openAppSettings=async function(){await e("plugin:barcode-scanner|open_app_settings")},n.requestPermissions=async function(){return await async function(n){return e(`plugin:${n}|request_permissions`)}("barcode-scanner").then((n=>n.camera))},n.scan=async function(n){return await e("plugin:barcode-scanner|scan",{...n})},n}({});Object.defineProperty(window.__TAURI__,"barcodeScanner",{value:__TAURI_PLUGIN_BARCODE_SCANNER__})}
+7 -8
View File
@@ -12,15 +12,14 @@ const COMMANDS: &[&str] = &[
];
fn main() {
if let Err(error) = tauri_plugin::Builder::new(COMMANDS)
let result = tauri_plugin::Builder::new(COMMANDS)
.global_api_script_path("./api-iife.js")
.android_path("android")
.ios_path("ios")
.try_build()
{
println!("{error:#}");
// when building documentation for Android the plugin build result is irrelevant to the crate itself
if !(cfg!(docsrs) && std::env::var("TARGET").unwrap().contains("android")) {
std::process::exit(1);
}
.try_build();
// when building documentation for Android the plugin build result is always Err() and is irrelevant to the crate documentation build
if !(cfg!(docsrs) && std::env::var("TARGET").unwrap().contains("android")) {
result.unwrap();
}
}
+34 -30
View File
@@ -2,36 +2,40 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
import { invoke } from "@tauri-apps/api/core";
import {
invoke,
requestPermissions as requestPermissions_,
checkPermissions as checkPermissions_
} from '@tauri-apps/api/core'
export type PermissionState = "granted" | "denied" | "prompt";
export type { PermissionState } from '@tauri-apps/api/core'
export enum Format {
QRCode = "QR_CODE",
UPC_A = "UPC_A",
UPC_E = "UPC_E",
EAN8 = "EAN_8",
EAN13 = "EAN_13",
Code39 = "CODE_39",
Code93 = "CODE_93",
Code128 = "CODE_128",
Codabar = "CODABAR",
ITF = "ITF",
Aztec = "AZTEC",
DataMatrix = "DATA_MATRIX",
PDF417 = "PDF_417",
QRCode = 'QR_CODE',
UPC_A = 'UPC_A',
UPC_E = 'UPC_E',
EAN8 = 'EAN_8',
EAN13 = 'EAN_13',
Code39 = 'CODE_39',
Code93 = 'CODE_93',
Code128 = 'CODE_128',
Codabar = 'CODABAR',
ITF = 'ITF',
Aztec = 'AZTEC',
DataMatrix = 'DATA_MATRIX',
PDF417 = 'PDF_417'
}
export interface ScanOptions {
cameraDirection?: "back" | "front";
formats?: Format[];
windowed?: boolean;
cameraDirection?: 'back' | 'front'
formats?: Format[]
windowed?: boolean
}
export interface Scanned {
content: string;
format: Format;
bounds: unknown;
content: string
format: Format
bounds: unknown
}
/**
@@ -39,37 +43,37 @@ export interface Scanned {
* @param options
*/
export async function scan(options?: ScanOptions): Promise<Scanned> {
return await invoke("plugin:barcode-scanner|scan", { ...options });
return await invoke('plugin:barcode-scanner|scan', { ...options })
}
/**
* Cancel the current scan process.
*/
export async function cancel(): Promise<void> {
return await invoke("plugin:barcode-scanner|cancel");
await invoke('plugin:barcode-scanner|cancel')
}
/**
* Get permission state.
*/
export async function checkPermissions(): Promise<PermissionState> {
return await invoke<{ camera: PermissionState }>(
"plugin:barcode-scanner|check_permissions",
).then((r) => r.camera);
return await checkPermissions_<{ camera: PermissionState }>(
'barcode-scanner'
).then((r) => r.camera)
}
/**
* Request permissions to use the camera.
*/
export async function requestPermissions(): Promise<PermissionState> {
return await invoke<{ camera: PermissionState }>(
"plugin:barcode-scanner|request_permissions",
).then((r) => r.camera);
return await requestPermissions_<{ camera: PermissionState }>(
'barcode-scanner'
).then((r) => r.camera)
}
/**
* Open application settings. Useful if permission was denied and the user must manually enable it.
*/
export async function openAppSettings(): Promise<void> {
return await invoke("plugin:barcode-scanner|open_app_settings");
await invoke('plugin:barcode-scanner|open_app_settings')
}
+2 -1
View File
@@ -10,7 +10,8 @@ import PackageDescription
let package = Package(
name: "tauri-plugin-barcode-scanner",
platforms: [
.iOS(.v13)
.macOS(.v10_13),
.iOS(.v13),
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
@@ -8,9 +8,9 @@ import UIKit
import WebKit
struct ScanOptions: Decodable {
var formats: [SupportedFormat] = []
let windowed: Bool?
let cameraDirection: String?
var formats: [SupportedFormat]?
var windowed: Bool?
var cameraDirection: String?
}
enum SupportedFormat: String, CaseIterable, Decodable {
@@ -241,7 +241,7 @@ class BarcodeScannerPlugin: Plugin, AVCaptureMetadataOutputObjectsDelegate {
private func runScanner(_ invoke: Invoke, args: ScanOptions) {
scanFormats = [AVMetadataObject.ObjectType]()
args.formats.forEach { format in
(args.formats ?? []).forEach { format in
scanFormats.append(format.value)
}
@@ -262,6 +262,13 @@ class BarcodeScannerPlugin: Plugin, AVCaptureMetadataOutputObjectsDelegate {
self.invoke = invoke
let entry = Bundle.main.infoDictionary?["NSCameraUsageDescription"] as? String
if entry == nil || entry?.count == 0 {
invoke.reject("NSCameraUsageDescription is not in the app Info.plist")
return
}
var iOS14min: Bool = false
if #available(iOS 14.0, *) { iOS14min = true }
if !iOS14min && self.getPermissionState() != "granted" {
+4 -3
View File
@@ -1,11 +1,12 @@
{
"name": "@tauri-apps/plugin-barcode-scanner",
"version": "2.0.0-beta.1",
"version": "2.0.0",
"description": "Scan QR codes, EAN-13 and other kinds of barcodes on Android and iOS",
"license": "MIT or APACHE-2.0",
"license": "MIT OR Apache-2.0",
"authors": [
"Tauri Programme within The Commons Conservancy"
],
"repository": "https://github.com/tauri-apps/plugins-workspace",
"type": "module",
"types": "./dist-js/index.d.ts",
"main": "./dist-js/index.cjs",
@@ -24,6 +25,6 @@
"LICENSE"
],
"dependencies": {
"@tauri-apps/api": "2.0.0-beta.2"
"@tauri-apps/api": "^2.0.0"
}
}
@@ -1,50 +1,183 @@
# Permissions
## Default Permission
## allow-cancel
This permission set configures which
barcode scanning features are by default exposed.
#### Granted Permissions
It allows all barcode related features.
- `allow-cancel`
- `allow-check-permissions`
- `allow-open-app-settings`
- `allow-request-permissions`
- `allow-scan`
- `allow-vibrate`
## Permission Table
<table>
<tr>
<th>Identifier</th>
<th>Description</th>
</tr>
<tr>
<td>
`barcode-scanner:allow-cancel`
</td>
<td>
Enables the cancel command without any pre-configured scope.
## deny-cancel
</td>
</tr>
<tr>
<td>
`barcode-scanner:deny-cancel`
</td>
<td>
Denies the cancel command without any pre-configured scope.
## allow-check-permissions
</td>
</tr>
<tr>
<td>
`barcode-scanner:allow-check-permissions`
</td>
<td>
Enables the check_permissions command without any pre-configured scope.
## deny-check-permissions
</td>
</tr>
<tr>
<td>
`barcode-scanner:deny-check-permissions`
</td>
<td>
Denies the check_permissions command without any pre-configured scope.
## allow-open-app-settings
</td>
</tr>
<tr>
<td>
`barcode-scanner:allow-open-app-settings`
</td>
<td>
Enables the open_app_settings command without any pre-configured scope.
## deny-open-app-settings
</td>
</tr>
<tr>
<td>
`barcode-scanner:deny-open-app-settings`
</td>
<td>
Denies the open_app_settings command without any pre-configured scope.
## allow-request-permissions
</td>
</tr>
<tr>
<td>
`barcode-scanner:allow-request-permissions`
</td>
<td>
Enables the request_permissions command without any pre-configured scope.
## deny-request-permissions
</td>
</tr>
<tr>
<td>
`barcode-scanner:deny-request-permissions`
</td>
<td>
Denies the request_permissions command without any pre-configured scope.
## allow-scan
</td>
</tr>
<tr>
<td>
`barcode-scanner:allow-scan`
</td>
<td>
Enables the scan command without any pre-configured scope.
## deny-scan
</td>
</tr>
<tr>
<td>
`barcode-scanner:deny-scan`
</td>
<td>
Denies the scan command without any pre-configured scope.
## allow-vibrate
</td>
</tr>
<tr>
<td>
`barcode-scanner:allow-vibrate`
</td>
<td>
Enables the vibrate command without any pre-configured scope.
## deny-vibrate
</td>
</tr>
<tr>
<td>
`barcode-scanner:deny-vibrate`
</td>
<td>
Denies the vibrate command without any pre-configured scope.
</td>
</tr>
</table>
@@ -0,0 +1,20 @@
"$schema" = "schemas/schema.json"
[default]
description = """
This permission set configures which
barcode scanning features are by default exposed.
#### Granted Permissions
It allows all barcode related features.
"""
permissions = [
"allow-cancel",
"allow-check-permissions",
"allow-open-app-settings",
"allow-request-permissions",
"allow-scan",
"allow-vibrate",
]
@@ -49,7 +49,7 @@
"minimum": 1.0
},
"description": {
"description": "Human-readable description of what the permission does.",
"description": "Human-readable description of what the permission does. Tauri convention is to use <h4> headings in markdown content for Tauri documentation generation purposes.",
"type": [
"string",
"null"
@@ -111,7 +111,7 @@
"type": "string"
},
"description": {
"description": "Human-readable description of what the permission does.",
"description": "Human-readable description of what the permission does. Tauri internal convention is to use <h4> headings in markdown content for Tauri documentation generation purposes.",
"type": [
"string",
"null"
@@ -136,6 +136,16 @@
"$ref": "#/definitions/Scopes"
}
]
},
"platforms": {
"description": "Target platforms this permission applies. By default all platforms are affected by this permission.",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/Target"
}
}
}
},
@@ -162,7 +172,7 @@
}
},
"Scopes": {
"description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.",
"description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command. The configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json { \"allow\": [{ \"path\": \"$HOME/**\" }], \"deny\": [{ \"path\": \"$HOME/secret.txt\" }] } ```",
"type": "object",
"properties": {
"allow": {
@@ -176,7 +186,7 @@
}
},
"deny": {
"description": "Data that defines what is denied by the scope.",
"description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.",
"type": [
"array",
"null"
@@ -241,92 +251,113 @@
}
]
},
"Target": {
"description": "Platform target.",
"oneOf": [
{
"description": "MacOS.",
"type": "string",
"enum": [
"macOS"
]
},
{
"description": "Windows.",
"type": "string",
"enum": [
"windows"
]
},
{
"description": "Linux.",
"type": "string",
"enum": [
"linux"
]
},
{
"description": "Android.",
"type": "string",
"enum": [
"android"
]
},
{
"description": "iOS.",
"type": "string",
"enum": [
"iOS"
]
}
]
},
"PermissionKind": {
"type": "string",
"oneOf": [
{
"description": "allow-cancel -> Enables the cancel command without any pre-configured scope.",
"description": "Enables the cancel command without any pre-configured scope.",
"type": "string",
"enum": [
"allow-cancel"
]
"const": "allow-cancel"
},
{
"description": "deny-cancel -> Denies the cancel command without any pre-configured scope.",
"description": "Denies the cancel command without any pre-configured scope.",
"type": "string",
"enum": [
"deny-cancel"
]
"const": "deny-cancel"
},
{
"description": "allow-check-permissions -> Enables the check_permissions command without any pre-configured scope.",
"description": "Enables the check_permissions command without any pre-configured scope.",
"type": "string",
"enum": [
"allow-check-permissions"
]
"const": "allow-check-permissions"
},
{
"description": "deny-check-permissions -> Denies the check_permissions command without any pre-configured scope.",
"description": "Denies the check_permissions command without any pre-configured scope.",
"type": "string",
"enum": [
"deny-check-permissions"
]
"const": "deny-check-permissions"
},
{
"description": "allow-open-app-settings -> Enables the open_app_settings command without any pre-configured scope.",
"description": "Enables the open_app_settings command without any pre-configured scope.",
"type": "string",
"enum": [
"allow-open-app-settings"
]
"const": "allow-open-app-settings"
},
{
"description": "deny-open-app-settings -> Denies the open_app_settings command without any pre-configured scope.",
"description": "Denies the open_app_settings command without any pre-configured scope.",
"type": "string",
"enum": [
"deny-open-app-settings"
]
"const": "deny-open-app-settings"
},
{
"description": "allow-request-permissions -> Enables the request_permissions command without any pre-configured scope.",
"description": "Enables the request_permissions command without any pre-configured scope.",
"type": "string",
"enum": [
"allow-request-permissions"
]
"const": "allow-request-permissions"
},
{
"description": "deny-request-permissions -> Denies the request_permissions command without any pre-configured scope.",
"description": "Denies the request_permissions command without any pre-configured scope.",
"type": "string",
"enum": [
"deny-request-permissions"
]
"const": "deny-request-permissions"
},
{
"description": "allow-scan -> Enables the scan command without any pre-configured scope.",
"description": "Enables the scan command without any pre-configured scope.",
"type": "string",
"enum": [
"allow-scan"
]
"const": "allow-scan"
},
{
"description": "deny-scan -> Denies the scan command without any pre-configured scope.",
"description": "Denies the scan command without any pre-configured scope.",
"type": "string",
"enum": [
"deny-scan"
]
"const": "deny-scan"
},
{
"description": "allow-vibrate -> Enables the vibrate command without any pre-configured scope.",
"description": "Enables the vibrate command without any pre-configured scope.",
"type": "string",
"enum": [
"allow-vibrate"
]
"const": "allow-vibrate"
},
{
"description": "deny-vibrate -> Denies the vibrate command without any pre-configured scope.",
"description": "Denies the vibrate command without any pre-configured scope.",
"type": "string",
"enum": [
"deny-vibrate"
]
"const": "deny-vibrate"
},
{
"description": "This permission set configures which\nbarcode scanning features are by default exposed.\n\n#### Granted Permissions\n\nIt allows all barcode related features.\n\n",
"type": "string",
"const": "default"
}
]
}
+2 -2
View File
@@ -2,6 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
import { createConfig } from "../../shared/rollup.config.js";
import { createConfig } from '../../shared/rollup.config.js'
export default createConfig();
export default createConfig()
-1
View File
@@ -1 +0,0 @@
if("__TAURI__"in window){var __TAURI_PLUGIN_BARCODESCANNER__=function(n){"use strict";async function e(n,e={},r){return window.__TAURI_INTERNALS__.invoke(n,e,r)}var r;return"function"==typeof SuppressedError&&SuppressedError,n.Format=void 0,(r=n.Format||(n.Format={})).QRCode="QR_CODE",r.UPC_A="UPC_A",r.UPC_E="UPC_E",r.EAN8="EAN_8",r.EAN13="EAN_13",r.Code39="CODE_39",r.Code93="CODE_93",r.Code128="CODE_128",r.Codabar="CODABAR",r.ITF="ITF",r.Aztec="AZTEC",r.DataMatrix="DATA_MATRIX",r.PDF417="PDF_417",n.cancel=async function(){return await e("plugin:barcode-scanner|cancel")},n.checkPermissions=async function(){return await e("plugin:barcode-scanner|check_permissions").then((n=>n.camera))},n.openAppSettings=async function(){return await e("plugin:barcode-scanner|open_app_settings")},n.requestPermissions=async function(){return await e("plugin:barcode-scanner|request_permissions").then((n=>n.camera))},n.scan=async function(n){return await e("plugin:barcode-scanner|scan",{...n})},n}({});Object.defineProperty(window.__TAURI__,"barcodeScanner",{value:__TAURI_PLUGIN_BARCODESCANNER__})}
+1 -1
View File
@@ -27,7 +27,7 @@ pub struct BarcodeScanner<R: Runtime>(PluginHandle<R>);
impl<R: Runtime> BarcodeScanner<R> {}
/// Extensions to [`tauri::App`], [`tauri::AppHandle`] and [`tauri::Window`] to access the barcode scanner APIs.
/// Extensions to [`tauri::App`], [`tauri::AppHandle`], [`tauri::WebviewWindow`], [`tauri::Webview`] and [`tauri::Window`] to access the barcode scanner APIs.
pub trait BarcodeScannerExt<R: Runtime> {
fn barcode_scanner(&self) -> &BarcodeScanner<R>;
}
+70 -1
View File
@@ -1,5 +1,64 @@
# Changelog
## \[2.0.1]
- [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7.
## \[2.0.0]
- [`e2c4dfb6`](https://github.com/tauri-apps/plugins-workspace/commit/e2c4dfb6af43e5dd8d9ceba232c315f5febd55c1) Update to tauri v2 stable release.
## \[2.0.0-rc.1]
- [`e2e97db5`](https://github.com/tauri-apps/plugins-workspace/commit/e2e97db51983267f5be84d4f6f0278d58834d1f5) ([#1701](https://github.com/tauri-apps/plugins-workspace/pull/1701) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Update to tauri 2.0.0-rc.8
## \[2.0.0-rc.2]
- [`b9147758`](https://github.com/tauri-apps/plugins-workspace/commit/b914775898c2bee7ceb20bd17ee595005cd17a64) ([#1679](https://github.com/tauri-apps/plugins-workspace/pull/1679) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Explicitly set a minimum macOS version for the Swift package.
## \[2.0.0-rc.1]
### changes
- [`6b079cfd`](https://github.com/tauri-apps/plugins-workspace/commit/6b079cfdd107c94abc2c7300f6af00bac3ff4040) ([#1649](https://github.com/tauri-apps/plugins-workspace/pull/1649) by [@ahqsoftwares](https://github.com/tauri-apps/plugins-workspace/../../ahqsoftwares)) Remove targetSdk from build.kts files as it is deprecated and will be removed from DSL v9.0
## \[2.0.0-rc.0]
- [`9887d1`](https://github.com/tauri-apps/plugins-workspace/commit/9887d14bd0e971c4c0f5c1188fc4005d3fc2e29e) Update to tauri RC.
## \[2.0.0-beta.8]
- [`99d6ac0f`](https://github.com/tauri-apps/plugins-workspace/commit/99d6ac0f9506a6a4a1aa59c728157190a7441af6) ([#1606](https://github.com/tauri-apps/plugins-workspace/pull/1606) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) The JS packages now specify the *minimum* `@tauri-apps/api` version instead of a single exact version.
- [`6de87966`](https://github.com/tauri-apps/plugins-workspace/commit/6de87966ecc00ad9d91c25be452f1f46bd2b7e1f) ([#1597](https://github.com/tauri-apps/plugins-workspace/pull/1597) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Update to tauri beta.25.
## \[2.0.0-beta.7]
- [`22a17980`](https://github.com/tauri-apps/plugins-workspace/commit/22a17980ff4f6f8c40adb1b8f4ffc6dae2fe7e30) ([#1537](https://github.com/tauri-apps/plugins-workspace/pull/1537) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Update to tauri beta.24.
## \[2.0.0-beta.6]
- [`76daee7a`](https://github.com/tauri-apps/plugins-workspace/commit/76daee7aafece34de3092c86e531cf9eb1138989) ([#1512](https://github.com/tauri-apps/plugins-workspace/pull/1512) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Update to tauri beta.23.
## \[2.0.0-beta.5]
- [`9013854f`](https://github.com/tauri-apps/plugins-workspace/commit/9013854f42a49a230b9dbb9d02774765528a923f)([#1382](https://github.com/tauri-apps/plugins-workspace/pull/1382)) Update to tauri beta.22.
## \[2.0.0-beta.4]
- [`430bd6f4`](https://github.com/tauri-apps/plugins-workspace/commit/430bd6f4f379bee5d232ae6b098ae131db7f178a)([#1363](https://github.com/tauri-apps/plugins-workspace/pull/1363)) Update to tauri beta.20.
## \[2.0.0-beta.3]
- [`bd1ed590`](https://github.com/tauri-apps/plugins-workspace/commit/bd1ed5903ffcce5500310dac1e59e8c67674ef1e)([#1237](https://github.com/tauri-apps/plugins-workspace/pull/1237)) Update to tauri beta.17.
## \[2.0.0-beta.3]
- [`a04ea2f`](https://github.com/tauri-apps/plugins-workspace/commit/a04ea2f38294d5a3987578283badc8eec87a7752)([#1071](https://github.com/tauri-apps/plugins-workspace/pull/1071)) The global API script is now only added to the binary when the `withGlobalTauri` config is true.
## \[2.0.0-beta.2]
- [`99bea25`](https://github.com/tauri-apps/plugins-workspace/commit/99bea2559c2c0648c2519c50a18cd124dacef57b)([#1005](https://github.com/tauri-apps/plugins-workspace/pull/1005)) Update to tauri beta.8.
## \[2.0.0-beta.1]
- [`569defb`](https://github.com/tauri-apps/plugins-workspace/commit/569defbe9492e38938554bb7bdc1be9151456d21) Update to tauri beta.4.
@@ -12,4 +71,14 @@
- [`8df28a9`](https://github.com/tauri-apps/plugins-workspace/commit/8df28a987519ecfa03dcb8635443025f8d010362)([#829](https://github.com/tauri-apps/plugins-workspace/pull/829)) Initial release.
- [`8df28a9`](https://github.com/tauri-apps/plugins-workspace/commit/8df28a987519ecfa03dcb8635443025f8d010362)([#829](https://github.com/tauri-apps/plugins-workspace/pull/829)) Initial release.
commit/8df28a987519ecfa03dcb8635443025f8d010362)([#829](https://github.com/tauri-apps/plugins-workspace/pull/829)) Initial release.
commit/8df28a987519ecfa03dcb8635443025f8d010362)([#829](https://github.com/tauri-apps/plugins-workspace/pull/829)) Initial release.
29]\(https://github.com/tauri-apps/plugins-workspace/pull/829)) Initial release.
commit/8df28a987519ecfa03dcb8635443025f8d010362)([#829](https://github.com/tauri-apps/plugins-workspace/pull/829)) Initial release.
.
commit/8df28a987519ecfa03dcb8635443025f8d010362)([#829](https://github.com/tauri-apps/plugins-workspace/pull/829)) Initial release.
itial release.
29]\(https://github.com/tauri-apps/plugins-workspace/pull/829)) Initial release.
commit/8df28a987519ecfa03dcb8635443025f8d010362)([#829](https://github.com/tauri-apps/plugins-workspace/pull/829)) Initial release.
.
commit/8df28a987519ecfa03dcb8635443025f8d010362)([#829](https://github.com/tauri-apps/plugins-workspace/pull/829)) Initial release.
ithub.com/tauri-apps/plugins-workspace/pull/829)) Initial release.
+14 -4
View File
@@ -1,18 +1,28 @@
[package]
name = "tauri-plugin-biometric"
version = "2.0.0-beta.1"
version = "2.0.1"
description = "Prompt the user for biometric authentication on Android and iOS."
edition = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
repository = { workspace = true }
links = "tauri-plugin-biometric"
[package.metadata.docs.rs]
rustc-args = [ "--cfg", "docsrs" ]
rustdoc-args = [ "--cfg", "docsrs" ]
rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs"]
targets = ["x86_64-linux-android"]
[package.metadata.platforms.support]
windows = { level = "none", notes = "" }
linux = { level = "none", notes = "" }
macos = { level = "none", notes = "" }
android = { level = "full", notes = "" }
ios = { level = "full", notes = "" }
[build-dependencies]
tauri-plugin = { workspace = true, features = [ "build" ] }
tauri-plugin = { workspace = true, features = ["build"] }
[dependencies]
serde = { workspace = true }
+11 -3
View File
@@ -2,6 +2,14 @@
Prompt the user for biometric authentication on Android and iOS.
| Platform | Supported |
| -------- | --------- |
| Linux | x |
| Windows | x |
| macOS | x |
| Android | ✓ |
| iOS | ✓ |
## Install
_This plugin requires a Rust version of at least **1.65**_
@@ -18,7 +26,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml
[dependencies]
tauri-plugin-biometric = "2.0.0-beta"
tauri-plugin-biometric = "2.0.0"
# alternatively with Git:
tauri-plugin-biometric = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
```
@@ -62,8 +70,8 @@ fn main() {
Afterwards all the plugin's APIs are available through the JavaScript guest bindings:
```javascript
import { authenticate } from "@tauri-apps/plugin-biometric";
await authenticate('Open your wallet');
import { authenticate } from '@tauri-apps/plugin-biometric'
await authenticate('Open your wallet')
```
## Contributing
+23
View File
@@ -0,0 +1,23 @@
# Security Policy
**Do not report security vulnerabilities through public GitHub issues.**
**Please use the [Private Vulnerability Disclosure](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability) feature of GitHub.**
Include as much of the following information:
- Type of issue (e.g. improper input parsing, privilege escalation, etc.)
- The location of the affected source code (tag/branch/commit or direct URL)
- Any special configuration required to reproduce the issue
- The distribution affected or used to help us with reproduction of the issue
- Step-by-step instructions to reproduce the issue
- Ideally a reproduction repository
- Impact of the issue, including how an attacker might exploit the issue
We prefer to receive reports in English.
## Contact
Please disclose a vulnerability or security relevant issue here: [https://github.com/tauri-apps/plugins-workspace/security/advisories/new](https://github.com/tauri-apps/plugins-workspace/security/advisories/new).
Alternatively, you can also contact us by email via [security@tauri.app](mailto:security@tauri.app).
+2 -3
View File
@@ -5,11 +5,10 @@ plugins {
android {
namespace = "app.tauri.biometric"
compileSdk = 32
compileSdk = 34
defaultConfig {
minSdk = 24
targetSdk = 32
minSdk = 24
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
@@ -115,6 +115,7 @@ class BiometricPlugin(private val activity: Activity): Plugin(activity) {
val biometryResult = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
manager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK)
} else {
@Suppress("DEPRECATION")
manager.canAuthenticate()
}
val ret = JSObject()
+1
View File
@@ -0,0 +1 @@
if("__TAURI__"in window){var __TAURI_PLUGIN_BIOMETRIC__=function(e){"use strict";async function i(e,i={},t){return window.__TAURI_INTERNALS__.invoke(e,i,t)}var t;return"function"==typeof SuppressedError&&SuppressedError,e.BiometryType=void 0,(t=e.BiometryType||(e.BiometryType={}))[t.None=0]="None",t[t.TouchID=1]="TouchID",t[t.FaceID=2]="FaceID",t[t.Iris=3]="Iris",e.authenticate=async function(e,t){await i("plugin:biometric|authenticate",{reason:e,...t})},e.checkStatus=async function(){return await i("plugin:biometric|status")},e}({});Object.defineProperty(window.__TAURI__,"biometric",{value:__TAURI_PLUGIN_BIOMETRIC__})}
+8 -2
View File
@@ -5,8 +5,14 @@
const COMMANDS: &[&str] = &["authenticate", "status"];
fn main() {
tauri_plugin::Builder::new(COMMANDS)
let result = tauri_plugin::Builder::new(COMMANDS)
.global_api_script_path("./api-iife.js")
.android_path("android")
.ios_path("ios")
.build();
.try_build();
// when building documentation for Android the plugin build result is always Err() and is irrelevant to the crate documentation build
if !(cfg!(docsrs) && std::env::var("TARGET").unwrap().contains("android")) {
result.unwrap();
}
}
+28 -28
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
import { invoke } from "@tauri-apps/api/core";
import { invoke } from '@tauri-apps/api/core'
export enum BiometryType {
None = 0,
@@ -11,39 +11,39 @@ export enum BiometryType {
// Apple FaceID or Android face authentication
FaceID = 2,
// Android iris authentication
Iris = 3,
Iris = 3
}
export interface Status {
isAvailable: boolean;
biometryType: BiometryType;
error?: string;
isAvailable: boolean
biometryType: BiometryType
error?: string
errorCode?:
| "appCancel"
| "authenticationFailed"
| "invalidContext"
| "notInteractive"
| "passcodeNotSet"
| "systemCancel"
| "userCancel"
| "userFallback"
| "biometryLockout"
| "biometryNotAvailable"
| "biometryNotEnrolled";
| 'appCancel'
| 'authenticationFailed'
| 'invalidContext'
| 'notInteractive'
| 'passcodeNotSet'
| 'systemCancel'
| 'userCancel'
| 'userFallback'
| 'biometryLockout'
| 'biometryNotAvailable'
| 'biometryNotEnrolled'
}
export interface AuthOptions {
allowDeviceCredential?: boolean;
cancelTitle?: string;
allowDeviceCredential?: boolean
cancelTitle?: string
// iOS options
fallbackTitle?: string;
fallbackTitle?: string
// android options
title?: string;
subtitle?: string;
confirmationRequired?: boolean;
maxAttemps?: number;
title?: string
subtitle?: string
confirmationRequired?: boolean
maxAttemps?: number
}
/**
@@ -51,7 +51,7 @@ export interface AuthOptions {
* @returns a promise resolving to an object containing all the information about the status of the biometry.
*/
export async function checkStatus(): Promise<Status> {
return invoke("plugin:biometric|status");
return await invoke('plugin:biometric|status')
}
/**
@@ -68,10 +68,10 @@ export async function checkStatus(): Promise<Status> {
*/
export async function authenticate(
reason: string,
options?: AuthOptions,
options?: AuthOptions
): Promise<void> {
return invoke("plugin:biometric|authenticate", {
await invoke('plugin:biometric|authenticate', {
reason,
...options,
});
...options
})
}
+2 -1
View File
@@ -8,7 +8,8 @@ import PackageDescription
let package = Package(
name: "tauri-plugin-biometric",
platforms: [
.iOS(.v13)
.macOS(.v10_13),
.iOS(.v13),
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
@@ -25,8 +25,8 @@ class BiometricStatus {
struct AuthOptions: Decodable {
let reason: String
var allowDeviceCredential: Bool?
let fallbackTitle: String?
let cancelTitle: String?
var fallbackTitle: String?
var cancelTitle: String?
}
class BiometricPlugin: Plugin {
+4 -6
View File
@@ -1,10 +1,11 @@
{
"name": "@tauri-apps/plugin-biometric",
"version": "2.0.0-beta.1",
"license": "MIT or APACHE-2.0",
"version": "2.0.0",
"license": "MIT OR Apache-2.0",
"authors": [
"Tauri Programme within The Commons Conservancy"
],
"repository": "https://github.com/tauri-apps/plugins-workspace",
"type": "module",
"types": "./dist-js/index.d.ts",
"main": "./dist-js/index.cjs",
@@ -23,10 +24,7 @@
"README.md",
"LICENSE"
],
"devDependencies": {
"tslib": "2.6.0"
},
"dependencies": {
"@tauri-apps/api": "2.0.0-beta.2"
"@tauri-apps/api": "^2.0.0"
}
}
@@ -1,18 +1,75 @@
# Permissions
## Default Permission
## allow-authenticate
This permission set configures which
biometric features are by default exposed.
#### Granted Permissions
It allows acccess to all biometric commands.
- `allow-authenticate`
- `allow-status`
## Permission Table
<table>
<tr>
<th>Identifier</th>
<th>Description</th>
</tr>
<tr>
<td>
`biometric:allow-authenticate`
</td>
<td>
Enables the authenticate command without any pre-configured scope.
## deny-authenticate
</td>
</tr>
<tr>
<td>
`biometric:deny-authenticate`
</td>
<td>
Denies the authenticate command without any pre-configured scope.
## allow-status
</td>
</tr>
<tr>
<td>
`biometric:allow-status`
</td>
<td>
Enables the status command without any pre-configured scope.
## deny-status
</td>
</tr>
<tr>
<td>
`biometric:deny-status`
</td>
<td>
Denies the status command without any pre-configured scope.
</td>
</tr>
</table>
@@ -0,0 +1,13 @@
"$schema" = "schemas/schema.json"
[default]
description = """
This permission set configures which
biometric features are by default exposed.
#### Granted Permissions
It allows acccess to all biometric commands.
"""
permissions = ["allow-authenticate", "allow-status"]
@@ -49,7 +49,7 @@
"minimum": 1.0
},
"description": {
"description": "Human-readable description of what the permission does.",
"description": "Human-readable description of what the permission does. Tauri convention is to use <h4> headings in markdown content for Tauri documentation generation purposes.",
"type": [
"string",
"null"
@@ -111,7 +111,7 @@
"type": "string"
},
"description": {
"description": "Human-readable description of what the permission does.",
"description": "Human-readable description of what the permission does. Tauri internal convention is to use <h4> headings in markdown content for Tauri documentation generation purposes.",
"type": [
"string",
"null"
@@ -136,6 +136,16 @@
"$ref": "#/definitions/Scopes"
}
]
},
"platforms": {
"description": "Target platforms this permission applies. By default all platforms are affected by this permission.",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/Target"
}
}
}
},
@@ -162,7 +172,7 @@
}
},
"Scopes": {
"description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.",
"description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command. The configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json { \"allow\": [{ \"path\": \"$HOME/**\" }], \"deny\": [{ \"path\": \"$HOME/secret.txt\" }] } ```",
"type": "object",
"properties": {
"allow": {
@@ -176,7 +186,7 @@
}
},
"deny": {
"description": "Data that defines what is denied by the scope.",
"description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.",
"type": [
"array",
"null"
@@ -241,36 +251,73 @@
}
]
},
"Target": {
"description": "Platform target.",
"oneOf": [
{
"description": "MacOS.",
"type": "string",
"enum": [
"macOS"
]
},
{
"description": "Windows.",
"type": "string",
"enum": [
"windows"
]
},
{
"description": "Linux.",
"type": "string",
"enum": [
"linux"
]
},
{
"description": "Android.",
"type": "string",
"enum": [
"android"
]
},
{
"description": "iOS.",
"type": "string",
"enum": [
"iOS"
]
}
]
},
"PermissionKind": {
"type": "string",
"oneOf": [
{
"description": "allow-authenticate -> Enables the authenticate command without any pre-configured scope.",
"description": "Enables the authenticate command without any pre-configured scope.",
"type": "string",
"enum": [
"allow-authenticate"
]
"const": "allow-authenticate"
},
{
"description": "deny-authenticate -> Denies the authenticate command without any pre-configured scope.",
"description": "Denies the authenticate command without any pre-configured scope.",
"type": "string",
"enum": [
"deny-authenticate"
]
"const": "deny-authenticate"
},
{
"description": "allow-status -> Enables the status command without any pre-configured scope.",
"description": "Enables the status command without any pre-configured scope.",
"type": "string",
"enum": [
"allow-status"
]
"const": "allow-status"
},
{
"description": "deny-status -> Denies the status command without any pre-configured scope.",
"description": "Denies the status command without any pre-configured scope.",
"type": "string",
"enum": [
"deny-status"
]
"const": "deny-status"
},
{
"description": "This permission set configures which\nbiometric features are by default exposed.\n\n#### Granted Permissions\n\nIt allows acccess to all biometric commands.\n\n",
"type": "string",
"const": "default"
}
]
}
+2 -2
View File
@@ -2,6 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
import { createConfig } from "../../shared/rollup.config.js";
import { createConfig } from '../../shared/rollup.config.js'
export default createConfig();
export default createConfig()
-1
View File
@@ -1 +0,0 @@
if("__TAURI__"in window){var __TAURI_PLUGIN_BIOMETRIC__=function(e){"use strict";async function n(e,n={},r){return window.__TAURI_INTERNALS__.invoke(e,n,r)}var r;return"function"==typeof SuppressedError&&SuppressedError,e.BiometryType=void 0,(r=e.BiometryType||(e.BiometryType={}))[r.None=0]="None",r[r.TouchID=1]="TouchID",r[r.FaceID=2]="FaceID",r[r.Iris=3]="Iris",e.authenticate=async function(e,r){return n("plugin:biometric|authenticate",{reason:e,...r})},e.checkStatus=async function(){return n("plugin:biometric|status")},e}({});Object.defineProperty(window.__TAURI__,"biometric",{value:__TAURI_PLUGIN_BIOMETRIC__})}
+1 -2
View File
@@ -45,7 +45,7 @@ impl<R: Runtime> Biometric<R> {
}
}
/// Extensions to [`tauri::App`], [`tauri::AppHandle`] and [`tauri::Window`] to access the biometric APIs.
/// Extensions to [`tauri::App`], [`tauri::AppHandle`], [`tauri::WebviewWindow`], [`tauri::Webview`] and [`tauri::Window`] to access the biometric APIs.
pub trait BiometricExt<R: Runtime> {
fn biometric(&self) -> &Biometric<R>;
}
@@ -59,7 +59,6 @@ impl<R: Runtime, T: Manager<R>> crate::BiometricExt<R> for T {
/// Initializes the plugin.
pub fn init<R: Runtime>() -> TauriPlugin<R> {
Builder::new("biometric")
.js_init_script(include_str!("api-iife.js").to_string())
.setup(|app, api| {
#[cfg(target_os = "android")]
let handle = api.register_android_plugin(PLUGIN_IDENTIFIER, "BiometricPlugin")?;
+7 -6
View File
@@ -7,16 +7,17 @@ use serde::{Deserialize, Serialize};
#[derive(Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AuthOptions {
/// Enables authentication using the device's password. This feature is available on both Android and iOS.
pub allow_device_credential: bool,
/// iOS only.
pub fallback_title: Option<String>,
/// iOS only.
/// Label for the Cancel button. This feature is available on both Android and iOS.
pub cancel_title: Option<String>,
/// Android only.
/// Specifies the text displayed on the fallback button if biometric authentication fails. This feature is available iOS only.
pub fallback_title: Option<String>,
/// Title indicating the purpose of biometric verification. This feature is available Android only.
pub title: Option<String>,
/// Android only.
/// SubTitle providing contextual information of biometric verification. This feature is available Android only.
pub subtitle: Option<String>,
/// Android only.
/// Specifies whether additional user confirmation is required, such as pressing a button after successful biometric authentication. This feature is available Android only.
pub confirmation_required: Option<bool>,
}
+55 -1
View File
@@ -1,5 +1,58 @@
# Changelog
## \[2.0.1]
- [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7.
## \[2.0.0]
- [`e2c4dfb6`](https://github.com/tauri-apps/plugins-workspace/commit/e2c4dfb6af43e5dd8d9ceba232c315f5febd55c1) Update to tauri v2 stable release.
## \[2.0.0-rc.2]
- [`68579934`](https://github.com/tauri-apps/plugins-workspace/commit/68579934c93f6ed2edbc97474560d6a8a00e8f70) ([#1856](https://github.com/tauri-apps/plugins-workspace/pull/1856) by [@amrbashir](https://github.com/tauri-apps/plugins-workspace/../../amrbashir)) Expose `Matches`, `SubcommandMatches` and `ArgData` structs.
## \[2.0.0-rc.1]
- [`e2e97db5`](https://github.com/tauri-apps/plugins-workspace/commit/e2e97db51983267f5be84d4f6f0278d58834d1f5) ([#1701](https://github.com/tauri-apps/plugins-workspace/pull/1701) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Update to tauri 2.0.0-rc.8
## \[2.0.0-rc.0]
- [`9887d1`](https://github.com/tauri-apps/plugins-workspace/commit/9887d14bd0e971c4c0f5c1188fc4005d3fc2e29e) Update to tauri RC.
## \[2.0.0-beta.8]
- [`99d6ac0f`](https://github.com/tauri-apps/plugins-workspace/commit/99d6ac0f9506a6a4a1aa59c728157190a7441af6) ([#1606](https://github.com/tauri-apps/plugins-workspace/pull/1606) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) The JS packages now specify the *minimum* `@tauri-apps/api` version instead of a single exact version.
- [`6de87966`](https://github.com/tauri-apps/plugins-workspace/commit/6de87966ecc00ad9d91c25be452f1f46bd2b7e1f) ([#1597](https://github.com/tauri-apps/plugins-workspace/pull/1597) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Update to tauri beta.25.
## \[2.0.0-beta.7]
- [`22a17980`](https://github.com/tauri-apps/plugins-workspace/commit/22a17980ff4f6f8c40adb1b8f4ffc6dae2fe7e30) ([#1537](https://github.com/tauri-apps/plugins-workspace/pull/1537) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Update to tauri beta.24.
## \[2.0.0-beta.6]
- [`76daee7a`](https://github.com/tauri-apps/plugins-workspace/commit/76daee7aafece34de3092c86e531cf9eb1138989) ([#1512](https://github.com/tauri-apps/plugins-workspace/pull/1512) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Update to tauri beta.23.
## \[2.0.0-beta.5]
- [`9013854f`](https://github.com/tauri-apps/plugins-workspace/commit/9013854f42a49a230b9dbb9d02774765528a923f)([#1382](https://github.com/tauri-apps/plugins-workspace/pull/1382)) Update to tauri beta.22.
## \[2.0.0-beta.4]
- [`430bd6f4`](https://github.com/tauri-apps/plugins-workspace/commit/430bd6f4f379bee5d232ae6b098ae131db7f178a)([#1363](https://github.com/tauri-apps/plugins-workspace/pull/1363)) Update to tauri beta.20.
## \[2.0.0-beta.3]
- [`bd1ed590`](https://github.com/tauri-apps/plugins-workspace/commit/bd1ed5903ffcce5500310dac1e59e8c67674ef1e)([#1237](https://github.com/tauri-apps/plugins-workspace/pull/1237)) Update to tauri beta.17.
## \[2.0.0-beta.3]
- [`a04ea2f`](https://github.com/tauri-apps/plugins-workspace/commit/a04ea2f38294d5a3987578283badc8eec87a7752)([#1071](https://github.com/tauri-apps/plugins-workspace/pull/1071)) The global API script is now only added to the binary when the `withGlobalTauri` config is true.
## \[2.0.0-beta.2]
- [`99bea25`](https://github.com/tauri-apps/plugins-workspace/commit/99bea2559c2c0648c2519c50a18cd124dacef57b)([#1005](https://github.com/tauri-apps/plugins-workspace/pull/1005)) Update to tauri beta.8.
## \[2.0.0-beta.1]
- [`569defb`](https://github.com/tauri-apps/plugins-workspace/commit/569defbe9492e38938554bb7bdc1be9151456d21) Update to tauri beta.4.
@@ -41,4 +94,5 @@
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
ae67\`]\(https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
om/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
+14 -5
View File
@@ -1,19 +1,28 @@
[package]
name = "tauri-plugin-cli"
version = "2.0.0-beta.1"
version = "2.0.1"
description = "Parse arguments from your Tauri application's command line interface."
edition = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
rust-version = { workspace = true }
repository = { workspace = true }
links = "tauri-plugin-cli"
[package.metadata.docs.rs]
rustc-args = [ "--cfg", "docsrs" ]
rustdoc-args = [ "--cfg", "docsrs" ]
rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs"]
[package.metadata.platforms.support]
windows = { level = "full", notes = "" }
linux = { level = "full", notes = "" }
macos = { level = "full", notes = "" }
android = { level = "none", notes = "" }
ios = { level = "none", notes = "" }
[build-dependencies]
tauri-plugin = { workspace = true, features = [ "build" ] }
tauri-plugin = { workspace = true, features = ["build"] }
[dependencies]
serde = { workspace = true }
@@ -21,4 +30,4 @@ serde_json = { workspace = true }
tauri = { workspace = true }
log = { workspace = true }
thiserror = { workspace = true }
clap = { version = "4", features = [ "string" ] }
clap = { version = "4", features = ["string"] }
+15 -9
View File
@@ -2,11 +2,17 @@
Parse arguments from your Command Line Interface.
- Supported platforms: Windows, Linux and macOS.
| Platform | Supported |
| -------- | --------- |
| Linux | ✓ |
| Windows | ✓ |
| macOS | ✓ |
| Android | x |
| iOS | x |
## Install
_This plugin requires a Rust version of at least **1.75**_
_This plugin requires a Rust version of at least **1.77.2**_
There are three general methods of installation that we can recommend.
@@ -21,7 +27,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml
# you can add the dependencies on the `[dependencies]` section if you do not target mobile
[target."cfg(not(any(target_os = \"android\", target_os = \"ios\")))".dependencies]
tauri-plugin-cli = "2.0.0-beta"
tauri-plugin-cli = "2.0.0"
# alternatively with Git:
tauri-plugin-cli = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
```
@@ -67,16 +73,16 @@ fn main() {
Afterwards all the plugin's APIs are available through the JavaScript guest bindings:
```javascript
import { getMatches } from "@tauri-apps/plugin-cli";
const matches = await getMatches();
if (matches.subcommand?.name === "run") {
import { getMatches } from '@tauri-apps/plugin-cli'
const matches = await getMatches()
if (matches.subcommand?.name === 'run') {
// `./your-app run $ARGS` was executed
const args = matches.subcommand?.matches.args;
if ("debug" in args) {
const args = matches.subcommand?.matches.args
if ('debug' in args) {
// `./your-app run --debug` was executed
}
} else {
const args = matches.args;
const args = matches.args
// `./your-app $ARGS` was executed
}
```
+23
View File
@@ -0,0 +1,23 @@
# Security Policy
**Do not report security vulnerabilities through public GitHub issues.**
**Please use the [Private Vulnerability Disclosure](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability) feature of GitHub.**
Include as much of the following information:
- Type of issue (e.g. improper input parsing, privilege escalation, etc.)
- The location of the affected source code (tag/branch/commit or direct URL)
- Any special configuration required to reproduce the issue
- The distribution affected or used to help us with reproduction of the issue
- Step-by-step instructions to reproduce the issue
- Ideally a reproduction repository
- Impact of the issue, including how an attacker might exploit the issue
We prefer to receive reports in English.
## Contact
Please disclose a vulnerability or security relevant issue here: [https://github.com/tauri-apps/plugins-workspace/security/advisories/new](https://github.com/tauri-apps/plugins-workspace/security/advisories/new).
Alternatively, you can also contact us by email via [security@tauri.app](mailto:security@tauri.app).
+3 -1
View File
@@ -5,5 +5,7 @@
const COMMANDS: &[&str] = &["cli_matches"];
fn main() {
tauri_plugin::Builder::new(COMMANDS).build();
tauri_plugin::Builder::new(COMMANDS)
.global_api_script_path("./api-iife.js")
.build();
}
+10 -10
View File
@@ -8,7 +8,7 @@
* @module
*/
import { invoke } from "@tauri-apps/api/core";
import { invoke } from '@tauri-apps/api/core'
/**
* @since 2.0.0
@@ -19,27 +19,27 @@ interface ArgMatch {
* boolean if flag
* string[] or null if takes multiple values
*/
value: string | boolean | string[] | null;
value: string | boolean | string[] | null
/**
* Number of occurrences
*/
occurrences: number;
occurrences: number
}
/**
* @since 2.0.0
*/
interface SubcommandMatch {
name: string;
matches: CliMatches;
name: string
matches: CliMatches
}
/**
* @since 2.0.0
*/
interface CliMatches {
args: Record<string, ArgMatch>;
subcommand: SubcommandMatch | null;
args: Record<string, ArgMatch>
subcommand: SubcommandMatch | null
}
/**
@@ -64,9 +64,9 @@ interface CliMatches {
* @since 2.0.0
*/
async function getMatches(): Promise<CliMatches> {
return await invoke("plugin:cli|cli_matches");
return await invoke('plugin:cli|cli_matches')
}
export type { ArgMatch, SubcommandMatch, CliMatches };
export type { ArgMatch, SubcommandMatch, CliMatches }
export { getMatches };
export { getMatches }
+4 -3
View File
@@ -1,10 +1,11 @@
{
"name": "@tauri-apps/plugin-cli",
"version": "2.0.0-beta.1",
"license": "MIT or APACHE-2.0",
"version": "2.0.0",
"license": "MIT OR Apache-2.0",
"authors": [
"Tauri Programme within The Commons Conservancy"
],
"repository": "https://github.com/tauri-apps/plugins-workspace",
"type": "module",
"types": "./dist-js/index.d.ts",
"main": "./dist-js/index.cjs",
@@ -23,6 +24,6 @@
"LICENSE"
],
"dependencies": {
"@tauri-apps/api": "2.0.0-beta.2"
"@tauri-apps/api": "^2.0.0"
}
}
@@ -1,14 +1,41 @@
# Permissions
## allow-cli-matches
Enables the cli_matches command without any pre-configured scope.
## deny-cli-matches
Denies the cli_matches command without any pre-configured scope.
## default
## Default Permission
Allows reading the CLI matches
- `allow-cli-matches`
## Permission Table
<table>
<tr>
<th>Identifier</th>
<th>Description</th>
</tr>
<tr>
<td>
`cli:allow-cli-matches`
</td>
<td>
Enables the cli_matches command without any pre-configured scope.
</td>
</tr>
<tr>
<td>
`cli:deny-cli-matches`
</td>
<td>
Denies the cli_matches command without any pre-configured scope.
</td>
</tr>
</table>
+60 -16
View File
@@ -49,7 +49,7 @@
"minimum": 1.0
},
"description": {
"description": "Human-readable description of what the permission does.",
"description": "Human-readable description of what the permission does. Tauri convention is to use <h4> headings in markdown content for Tauri documentation generation purposes.",
"type": [
"string",
"null"
@@ -111,7 +111,7 @@
"type": "string"
},
"description": {
"description": "Human-readable description of what the permission does.",
"description": "Human-readable description of what the permission does. Tauri internal convention is to use <h4> headings in markdown content for Tauri documentation generation purposes.",
"type": [
"string",
"null"
@@ -136,6 +136,16 @@
"$ref": "#/definitions/Scopes"
}
]
},
"platforms": {
"description": "Target platforms this permission applies. By default all platforms are affected by this permission.",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/Target"
}
}
}
},
@@ -162,7 +172,7 @@
}
},
"Scopes": {
"description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.",
"description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command. The configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json { \"allow\": [{ \"path\": \"$HOME/**\" }], \"deny\": [{ \"path\": \"$HOME/secret.txt\" }] } ```",
"type": "object",
"properties": {
"allow": {
@@ -176,7 +186,7 @@
}
},
"deny": {
"description": "Data that defines what is denied by the scope.",
"description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.",
"type": [
"array",
"null"
@@ -241,29 +251,63 @@
}
]
},
"Target": {
"description": "Platform target.",
"oneOf": [
{
"description": "MacOS.",
"type": "string",
"enum": [
"macOS"
]
},
{
"description": "Windows.",
"type": "string",
"enum": [
"windows"
]
},
{
"description": "Linux.",
"type": "string",
"enum": [
"linux"
]
},
{
"description": "Android.",
"type": "string",
"enum": [
"android"
]
},
{
"description": "iOS.",
"type": "string",
"enum": [
"iOS"
]
}
]
},
"PermissionKind": {
"type": "string",
"oneOf": [
{
"description": "allow-cli-matches -> Enables the cli_matches command without any pre-configured scope.",
"description": "Enables the cli_matches command without any pre-configured scope.",
"type": "string",
"enum": [
"allow-cli-matches"
]
"const": "allow-cli-matches"
},
{
"description": "deny-cli-matches -> Denies the cli_matches command without any pre-configured scope.",
"description": "Denies the cli_matches command without any pre-configured scope.",
"type": "string",
"enum": [
"deny-cli-matches"
]
"const": "deny-cli-matches"
},
{
"description": "default -> Allows reading the CLI matches",
"description": "Allows reading the CLI matches",
"type": "string",
"enum": [
"default"
]
"const": "default"
}
]
}
+2 -2
View File
@@ -2,6 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
import { createConfig } from "../../shared/rollup.config.js";
import { createConfig } from '../../shared/rollup.config.js'
export default createConfig();
export default createConfig()
+2
View File
@@ -18,3 +18,5 @@ impl Serialize for Error {
serializer.serialize_str(self.to_string().as_ref())
}
}
pub type Result<T> = std::result::Result<T, Error>;
+3 -3
View File
@@ -23,8 +23,9 @@ mod error;
mod parser;
use config::{Arg, Config};
pub use error::Error;
type Result<T> = std::result::Result<T, Error>;
pub use error::{Error, Result};
pub use parser::{ArgData, Matches, SubcommandMatches};
pub struct Cli<R: Runtime>(PluginApi<R, Config>);
@@ -51,7 +52,6 @@ fn cli_matches<R: Runtime>(_app: AppHandle<R>, cli: State<'_, Cli<R>>) -> Result
pub fn init<R: Runtime>() -> TauriPlugin<R, Config> {
Builder::new("cli")
.js_init_script(include_str!("api-iife.js").to_string())
.invoke_handler(tauri::generate_handler![cli_matches])
.setup(|app, api| {
app.manage(Cli(api));
+102 -1
View File
@@ -1,5 +1,77 @@
# Changelog
## \[2.0.1]
- [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7.
## \[2.0.0]
- [`e2c4dfb6`](https://github.com/tauri-apps/plugins-workspace/commit/e2c4dfb6af43e5dd8d9ceba232c315f5febd55c1) Update to tauri v2 stable release.
## \[2.0.0-rc.2]
- [`341a5320`](https://github.com/tauri-apps/plugins-workspace/commit/341a5320c33d3c7b041abf7eb0ab7ad8009e6c3f) ([#1771](https://github.com/tauri-apps/plugins-workspace/pull/1771)) Fix warnings and clear implementation on Android below SDK 28.
## \[2.0.0-rc.1]
- [`e2e97db5`](https://github.com/tauri-apps/plugins-workspace/commit/e2e97db51983267f5be84d4f6f0278d58834d1f5) ([#1701](https://github.com/tauri-apps/plugins-workspace/pull/1701) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Update to tauri 2.0.0-rc.8
## \[2.0.0-rc.2]
- [`b9147758`](https://github.com/tauri-apps/plugins-workspace/commit/b914775898c2bee7ceb20bd17ee595005cd17a64) ([#1679](https://github.com/tauri-apps/plugins-workspace/pull/1679) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Explicitly set a minimum macOS version for the Swift package.
## \[2.0.0-rc.1]
- [`2c00c029`](https://github.com/tauri-apps/plugins-workspace/commit/2c00c0292c9127b81567de46691e8c0f73557261) ([#1630](https://github.com/tauri-apps/plugins-workspace/pull/1630) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Fixed an issue that caused multi-word IIFE names to not be formatted correctly. For example the `barcode-scanner` was defined as `window.__TAURI_PLUGIN_CLIPBOARDMANAGER__` instead of `window.__TAURI_PLUGIN_CLIPBOARD_MANAGER__`.
### changes
- [`6b079cfd`](https://github.com/tauri-apps/plugins-workspace/commit/6b079cfdd107c94abc2c7300f6af00bac3ff4040) ([#1649](https://github.com/tauri-apps/plugins-workspace/pull/1649) by [@ahqsoftwares](https://github.com/tauri-apps/plugins-workspace/../../ahqsoftwares)) Remove targetSdk from build.kts files as it is deprecated and will be removed from DSL v9.0
## \[2.0.0-rc.0]
- [`9887d1`](https://github.com/tauri-apps/plugins-workspace/commit/9887d14bd0e971c4c0f5c1188fc4005d3fc2e29e) Update to tauri RC.
## \[2.1.0-beta.6]
- [`99d6ac0f`](https://github.com/tauri-apps/plugins-workspace/commit/99d6ac0f9506a6a4a1aa59c728157190a7441af6) ([#1606](https://github.com/tauri-apps/plugins-workspace/pull/1606) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) The JS packages now specify the *minimum* `@tauri-apps/api` version instead of a single exact version.
- [`6de87966`](https://github.com/tauri-apps/plugins-workspace/commit/6de87966ecc00ad9d91c25be452f1f46bd2b7e1f) ([#1597](https://github.com/tauri-apps/plugins-workspace/pull/1597) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Update to tauri beta.25.
## \[2.1.0-beta.5]
- [`22a17980`](https://github.com/tauri-apps/plugins-workspace/commit/22a17980ff4f6f8c40adb1b8f4ffc6dae2fe7e30) ([#1537](https://github.com/tauri-apps/plugins-workspace/pull/1537) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Update to tauri beta.24.
## \[2.1.0-beta.4]
- [`76daee7a`](https://github.com/tauri-apps/plugins-workspace/commit/76daee7aafece34de3092c86e531cf9eb1138989) ([#1512](https://github.com/tauri-apps/plugins-workspace/pull/1512) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Update to tauri beta.23.
## \[2.1.0-beta.3]
- [`9013854f`](https://github.com/tauri-apps/plugins-workspace/commit/9013854f42a49a230b9dbb9d02774765528a923f)([#1382](https://github.com/tauri-apps/plugins-workspace/pull/1382)) Update to tauri beta.22.
## \[2.1.0-beta.2]
- [`430bd6f4`](https://github.com/tauri-apps/plugins-workspace/commit/430bd6f4f379bee5d232ae6b098ae131db7f178a)([#1363](https://github.com/tauri-apps/plugins-workspace/pull/1363)) Update to tauri beta.20.
## \[2.1.0-beta.1]
- [`bd1ed590`](https://github.com/tauri-apps/plugins-workspace/commit/bd1ed5903ffcce5500310dac1e59e8c67674ef1e)([#1237](https://github.com/tauri-apps/plugins-workspace/pull/1237)) Update to tauri beta.17.
## \[2.1.0-beta.1]
- [`27b258c`](https://github.com/tauri-apps/plugins-workspace/commit/27b258cf31ae5557c99ae66537fb9196368d4d8b)([#1185](https://github.com/tauri-apps/plugins-workspace/pull/1185)) Expose `Clipboard` struct
- [`e3d41f4`](https://github.com/tauri-apps/plugins-workspace/commit/e3d41f4011bd3ea3ce281bb38bbe31d3709f8e0f)([#1191](https://github.com/tauri-apps/plugins-workspace/pull/1191)) Internally use the webview scoped resources table instead of the app one, so other webviews can't access other webviews resources.
- [`e3d41f4`](https://github.com/tauri-apps/plugins-workspace/commit/e3d41f4011bd3ea3ce281bb38bbe31d3709f8e0f)([#1191](https://github.com/tauri-apps/plugins-workspace/pull/1191)) Update for tauri 2.0.0-beta.15.
## \[2.1.0-beta.0]
- [`9dec960`](https://github.com/tauri-apps/plugins-workspace/commit/9dec9605ed1ce19dbef697e55debddf9008ecba1)([#845](https://github.com/tauri-apps/plugins-workspace/pull/845)) Add support for `read_image` and `write_image` to the clipboard plugin (desktop).
## \[2.0.0-beta.2]
- [`dc6d332`](https://github.com/tauri-apps/plugins-workspace/commit/dc6d3321e5305fa8b7250553bd179cbee995998a)([#977](https://github.com/tauri-apps/plugins-workspace/pull/977)) Add support for writing HTML content to the clipboard.
- [`99bea25`](https://github.com/tauri-apps/plugins-workspace/commit/99bea2559c2c0648c2519c50a18cd124dacef57b)([#1005](https://github.com/tauri-apps/plugins-workspace/pull/1005)) Update to tauri beta.8.
## \[2.0.0-beta.1]
- [`569defb`](https://github.com/tauri-apps/plugins-workspace/commit/569defbe9492e38938554bb7bdc1be9151456d21) Update to tauri beta.4.
@@ -41,4 +113,33 @@
## \[2.0.0-alpha.0]
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
\`]\(https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
te to alpha.11.
## \[2.0.0-alpha.0]
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
hub.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
\`]\(https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
te to alpha.11.
## \[2.0.0-alpha.0]
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
te to alpha.11.
## \[2.0.0-alpha.0]
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
!
717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
ps/plugins-workspace/pull/371)) First v2 alpha release!
717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
!
717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
om/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
+18 -5
View File
@@ -1,20 +1,29 @@
[package]
name = "tauri-plugin-clipboard-manager"
version = "2.0.0-beta.1"
version = "2.0.1"
description = "Read and write to the system clipboard."
edition = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
rust-version = { workspace = true }
repository = { workspace = true }
links = "tauri-plugin-clipboard-manager"
[package.metadata.docs.rs]
rustc-args = [ "--cfg", "docsrs" ]
rustdoc-args = [ "--cfg", "docsrs" ]
targets = [ "x86_64-unknown-linux-gnu", "x86_64-linux-android" ]
rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs"]
targets = ["x86_64-unknown-linux-gnu", "x86_64-linux-android"]
[package.metadata.platforms.support]
windows = { level = "full", notes = "" }
linux = { level = "full", notes = "" }
macos = { level = "full", notes = "" }
android = { level = "partial", notes = "Only plain-text content support" }
ios = { level = "partial", notes = "Only plain-text content support" }
[build-dependencies]
tauri-plugin = { workspace = true, features = [ "build" ] }
tauri-plugin = { workspace = true, features = ["build"] }
[dependencies]
serde = { workspace = true }
@@ -23,5 +32,9 @@ tauri = { workspace = true }
log = { workspace = true }
thiserror = { workspace = true }
[target.'cfg(target_os = "ios")'.dependencies]
tauri = { workspace = true, features = ["wry"] }
[target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
arboard = "3"
image = "0.25"
+19 -5
View File
@@ -2,9 +2,17 @@
Read and write to the system clipboard.
| Platform | Supported |
| -------- | --------- |
| Linux | ✓ |
| Windows | ✓ |
| macOS | ✓ |
| Android | ✓ |
| iOS | ✓ |
## Install
_This plugin requires a Rust version of at least **1.75**_
_This plugin requires a Rust version of at least **1.77.2**_
There are three general methods of installation that we can recommend.
@@ -18,7 +26,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml
[dependencies]
tauri-plugin-clipboard-manager = "2.0.0-beta"
tauri-plugin-clipboard-manager = "2.0.0"
# alternatively with Git:
tauri-plugin-clipboard-manager = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
```
@@ -60,9 +68,15 @@ fn main() {
Afterwards all the plugin's APIs are available through the JavaScript guest bindings:
```javascript
import { writeText, readText, writeHtml, readHtml, clear } from "@tauri-apps/plugin-clipboard-manager";
await writeText("Tauri is awesome!");
assert(await readText(), "Tauri is awesome!");
import {
writeText,
readText,
writeHtml,
readHtml,
clear
} from '@tauri-apps/plugin-clipboard-manager'
await writeText('Tauri is awesome!')
assert(await readText(), 'Tauri is awesome!')
```
## Contributing
+23
View File
@@ -0,0 +1,23 @@
# Security Policy
**Do not report security vulnerabilities through public GitHub issues.**
**Please use the [Private Vulnerability Disclosure](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability) feature of GitHub.**
Include as much of the following information:
- Type of issue (e.g. improper input parsing, privilege escalation, etc.)
- The location of the affected source code (tag/branch/commit or direct URL)
- Any special configuration required to reproduce the issue
- The distribution affected or used to help us with reproduction of the issue
- Step-by-step instructions to reproduce the issue
- Ideally a reproduction repository
- Impact of the issue, including how an attacker might exploit the issue
We prefer to receive reports in English.
## Contact
Please disclose a vulnerability or security relevant issue here: [https://github.com/tauri-apps/plugins-workspace/security/advisories/new](https://github.com/tauri-apps/plugins-workspace/security/advisories/new).
Alternatively, you can also contact us by email via [security@tauri.app](mailto:security@tauri.app).
@@ -5,11 +5,10 @@ plugins {
android {
namespace = "app.tauri.clipboard"
compileSdk = 32
compileSdk = 34
defaultConfig {
minSdk = 24
targetSdk = 32
minSdk = 24
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
@@ -4,12 +4,12 @@
package app.tauri.clipboard
import android.R.attr.value
import android.app.Activity
import android.content.ClipData
import android.content.ClipDescription
import android.content.ClipboardManager
import android.content.Context
import android.os.Build
import app.tauri.annotation.Command
import app.tauri.annotation.InvokeArg
import app.tauri.annotation.TauriPlugin
@@ -59,7 +59,9 @@ internal class ReadClipDataSerializer @JvmOverloads constructor(t: Class<ReadCli
jgen.writeEndObject()
}
else -> {}
else -> {
throw Exception("unimplemented ReadClipData")
}
}
jgen.writeEndObject()
@@ -87,17 +89,17 @@ class ClipboardPlugin(private val activity: Activity) : Plugin(activity) {
@Command
@Suppress("MoveVariableDeclarationIntoWhen")
fun write(invoke: Invoke) {
fun writeText(invoke: Invoke) {
val args = invoke.parseArgs(WriteOptions::class.java)
val clipData = when (args) {
is WriteOptions.PlainText -> {
ClipData.newPlainText(args.label, args.text)
}
else -> {
invoke.reject("unimplemented clip data")
} else -> {
invoke.reject("unimplemented WriteOptions")
return
}
}
manager.setPrimaryClip(clipData)
@@ -106,7 +108,7 @@ class ClipboardPlugin(private val activity: Activity) : Plugin(activity) {
}
@Command
fun read(invoke: Invoke) {
fun readText(invoke: Invoke) {
val data = if (manager.hasPrimaryClip()) {
if (manager.primaryClipDescription?.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN) == true) {
val item: ClipData.Item = manager.primaryClip!!.getItemAt(0)
@@ -125,4 +127,16 @@ class ClipboardPlugin(private val activity: Activity) : Plugin(activity) {
invoke.resolveObject(data)
}
@Command
fun clear(invoke: Invoke) {
if (manager.hasPrimaryClip()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
manager.clearPrimaryClip()
} else {
manager.setPrimaryClip(ClipData.newPlainText("", ""))
}
}
invoke.resolve()
}
}
+1
View File
@@ -0,0 +1 @@
if("__TAURI__"in window){var __TAURI_PLUGIN_CLIPBOARD_MANAGER__=function(e){"use strict";var t;async function r(e,t={},r){return window.__TAURI_INTERNALS__.invoke(e,t,r)}"function"==typeof SuppressedError&&SuppressedError;class n{get rid(){return function(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)}(this,t,"f")}constructor(e){t.set(this,void 0),function(e,t,r,n,a){if("function"==typeof t?e!==t||!a:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");t.set(e,r)}(this,t,e)}async close(){return r("plugin:resources|close",{rid:this.rid})}}t=new WeakMap;class a extends n{constructor(e){super(e)}static async new(e,t,n){return r("plugin:image|new",{rgba:i(e),width:t,height:n}).then((e=>new a(e)))}static async fromBytes(e){return r("plugin:image|from_bytes",{bytes:i(e)}).then((e=>new a(e)))}static async fromPath(e){return r("plugin:image|from_path",{path:e}).then((e=>new a(e)))}async rgba(){return r("plugin:image|rgba",{rid:this.rid}).then((e=>new Uint8Array(e)))}async size(){return r("plugin:image|size",{rid:this.rid})}}function i(e){return null==e?null:"string"==typeof e?e:e instanceof a?e.rid:e}return e.clear=async function(){await r("plugin:clipboard-manager|clear")},e.readImage=async function(){return await r("plugin:clipboard-manager|read_image").then((e=>new a(e)))},e.readText=async function(){return await r("plugin:clipboard-manager|read_text")},e.writeHtml=async function(e,t){await r("plugin:clipboard-manager|write_html",{html:e,altHtml:t})},e.writeImage=async function(e){await r("plugin:clipboard-manager|write_image",{image:i(e)})},e.writeText=async function(e,t){await r("plugin:clipboard-manager|write_text",{label:t?.label,text:e})},e}({});Object.defineProperty(window.__TAURI__,"clipboardManager",{value:__TAURI_PLUGIN_CLIPBOARD_MANAGER__})}
+15 -9
View File
@@ -2,18 +2,24 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
const COMMANDS: &[&str] = &["write", "read"];
const COMMANDS: &[&str] = &[
"write_text",
"read_text",
"write_image",
"read_image",
"write_html",
"clear",
];
fn main() {
if let Err(error) = tauri_plugin::Builder::new(COMMANDS)
let result = tauri_plugin::Builder::new(COMMANDS)
.global_api_script_path("./api-iife.js")
.android_path("android")
.ios_path("ios")
.try_build()
{
println!("{error:#}");
// when building documentation for Android the plugin build result is irrelevant to the crate itself
if !(cfg!(docsrs) && std::env::var("TARGET").unwrap().contains("android")) {
std::process::exit(1);
}
.try_build();
// when building documentation for Android the plugin build result is always Err() and is irrelevant to the crate documentation build
if !(cfg!(docsrs) && std::env::var("TARGET").unwrap().contains("android")) {
result.unwrap();
}
}
+79 -26
View File
@@ -8,9 +8,8 @@
* @module
*/
import { invoke } from "@tauri-apps/api/core";
type ClipResponse = Record<"plainText", { text: string }>;
import { invoke } from '@tauri-apps/api/core'
import { Image, transformImage } from '@tauri-apps/api/image'
/**
* Writes plain text to the clipboard.
@@ -27,16 +26,12 @@ type ClipResponse = Record<"plainText", { text: string }>;
*/
async function writeText(
text: string,
opts?: { label?: string },
opts?: { label?: string }
): Promise<void> {
return invoke("plugin:clipboard-manager|write", {
data: {
plainText: {
label: opts?.label,
text,
},
},
});
await invoke('plugin:clipboard-manager|write_text', {
label: opts?.label,
text
})
}
/**
@@ -49,12 +44,70 @@ async function writeText(
* @since 2.0.0
*/
async function readText(): Promise<string> {
const kind: ClipResponse = await invoke("plugin:clipboard-manager|read");
return kind.plainText.text;
return await invoke('plugin:clipboard-manager|read_text')
}
/**
* Writes HTML or fallbacks to write provided plain text to the clipboard.
* Writes image buffer to the clipboard.
*
* #### Platform-specific
*
* - **Android / iOS:** Not supported.
*
* @example
* ```typescript
* import { writeImage } from '@tauri-apps/plugin-clipboard-manager';
* const buffer = [
* // A red pixel
* 255, 0, 0, 255,
*
* // A green pixel
* 0, 255, 0, 255,
* ];
* await writeImage(buffer);
*
* @returns A promise indicating the success or failure of the operation.
*
* @since 2.0.0
*/
async function writeImage(
image: string | Image | Uint8Array | ArrayBuffer | number[]
): Promise<void> {
await invoke('plugin:clipboard-manager|write_image', {
image: transformImage(image)
})
}
/**
* Gets the clipboard content as Uint8Array image.
*
* #### Platform-specific
*
* - **Android / iOS:** Not supported.
*
* @example
* ```typescript
* import { readImage } from '@tauri-apps/plugin-clipboard-manager';
*
* const clipboardImage = await readImage();
* const blob = new Blob([clipboardImage.bytes], { type: 'image' })
* const url = URL.createObjectURL(blob)
* ```
* @since 2.0.0
*/
async function readImage(): Promise<Image> {
return await invoke<number>('plugin:clipboard-manager|read_image').then(
(rid) => new Image(rid)
)
}
/**
* * Writes HTML or fallbacks to write provided plain text to the clipboard.
*
* #### Platform-specific
*
* - **Android / iOS:** Not supported.
*
* @example
* ```typescript
* import { writeHtml, readHtml } from '@tauri-apps/plugin-clipboard-manager';
@@ -68,18 +121,19 @@ async function readText(): Promise<string> {
* @since 2.0.0
*/
async function writeHtml(html: string, altHtml?: string): Promise<void> {
return invoke("plugin:clipboard-manager|write_html", {
data: {
html: {
html,
altHtml,
},
},
});
await invoke('plugin:clipboard-manager|write_html', {
html,
altHtml
})
}
/**
* Clears the clipboard.
*
* #### Platform-specific
*
* - **Android:** Only supported on SDK 28+. For older releases we write an empty string to the clipboard instead.
*
* @example
* ```typescript
* import { clear } from '@tauri-apps/plugin-clipboard-manager';
@@ -88,8 +142,7 @@ async function writeHtml(html: string, altHtml?: string): Promise<void> {
* @since 2.0.0
*/
async function clear(): Promise<void> {
await invoke("plugin:clipboard-manager|clear");
return;
await invoke('plugin:clipboard-manager|clear')
}
export { writeText, readText, writeHtml, clear };
export { writeText, readText, writeHtml, clear, readImage, writeImage }

Some files were not shown because too many files have changed in this diff Show More