mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-06-06 13:53:54 +02:00
Merge branch 'v2' into feat/shell-show-item-in-dir
This commit is contained in:
@@ -1 +0,0 @@
|
||||
node_modules
|
||||
@@ -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!
|
||||
@@ -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"
|
||||
@@ -1,143 +0,0 @@
|
||||

|
||||
|
||||
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 |
@@ -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();
|
||||
}
|
||||
@@ -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 +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__})}
|
||||
@@ -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(®ister_data));
|
||||
println!("Device info: {}", &device_info);
|
||||
|
||||
let (key_handle, public_key) =
|
||||
_u2f_get_key_handle_and_public_key_from_register_response(®ister_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(®ister_data);
|
||||
println!("Key Handle: {}", &key_handle_base64);
|
||||
println!("Public Key: {}", &public_key_base64);
|
||||
|
||||
// Ok(base64::encode(®ister_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))
|
||||
}
|
||||
@@ -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/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()
|
||||
}
|
||||
@@ -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(®.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 +0,0 @@
|
||||
node_modules
|
||||
@@ -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!
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||

|
||||
|
||||
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
|
||||
|
||||
@@ -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,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();
|
||||
}
|
||||
|
||||
@@ -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')
|
||||
}
|
||||
|
||||
@@ -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,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()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"] }
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||

|
||||

|
||||
|
||||
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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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__})}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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')
|
||||
}
|
||||
|
||||
@@ -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" {
|
||||
|
||||
@@ -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,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 +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__})}
|
||||
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.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()
|
||||
|
||||
@@ -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__})}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,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 +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__})}
|
||||
@@ -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,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>,
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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,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();
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,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()
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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!
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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__})}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user