feat: 生成PhizPay私钥和证书功能

main
Zaeyee 2024-08-30 17:56:25 +08:00
parent 203881c5b2
commit 5848155bba
7 changed files with 293 additions and 58 deletions

View File

@ -1,5 +1,5 @@
{
"name": "tauri-app",
"name": "phiz-pay-tools",
"private": true,
"version": "0.1.0",
"type": "module",

150
src-tauri/Cargo.lock generated
View File

@ -306,8 +306,10 @@ checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"serde",
"wasm-bindgen",
"windows-targets 0.52.6",
]
@ -1649,6 +1651,17 @@ dependencies = [
"objc_exception",
]
[[package]]
name = "objc-foundation"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
dependencies = [
"block",
"objc",
"objc_id",
]
[[package]]
name = "objc_exception"
version = "0.1.2"
@ -1692,6 +1705,44 @@ dependencies = [
"windows-sys 0.42.0",
]
[[package]]
name = "openssl"
version = "0.10.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1"
dependencies = [
"bitflags 2.6.0",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.76",
]
[[package]]
name = "openssl-sys"
version = "0.9.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "overload"
version = "0.1.1"
@ -2175,6 +2226,30 @@ version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]]
name = "rfd"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0149778bd99b6959285b0933288206090c50e2327f47a9c463bfdbf45c8823ea"
dependencies = [
"block",
"dispatch",
"glib-sys",
"gobject-sys",
"gtk-sys",
"js-sys",
"lazy_static",
"log",
"objc",
"objc-foundation",
"objc_id",
"raw-window-handle",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"windows 0.37.0",
]
[[package]]
name = "rustc-demangle"
version = "0.1.24"
@ -2659,6 +2734,7 @@ dependencies = [
"rand 0.8.5",
"raw-window-handle",
"regex",
"rfd",
"semver",
"serde",
"serde_json",
@ -2684,10 +2760,13 @@ dependencies = [
name = "tauri-app"
version = "0.1.0"
dependencies = [
"chrono",
"openssl",
"serde",
"serde_json",
"tauri",
"tauri-build",
"thiserror",
]
[[package]]
@ -3142,6 +3221,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version-compare"
version = "0.0.11"
@ -3228,6 +3313,18 @@ dependencies = [
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed"
dependencies = [
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.93"
@ -3257,6 +3354,16 @@ version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
[[package]]
name = "web-sys"
version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "webkit2gtk"
version = "0.18.2"
@ -3373,6 +3480,19 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647"
dependencies = [
"windows_aarch64_msvc 0.37.0",
"windows_i686_gnu 0.37.0",
"windows_i686_msvc 0.37.0",
"windows_x86_64_gnu 0.37.0",
"windows_x86_64_msvc 0.37.0",
]
[[package]]
name = "windows"
version = "0.39.0"
@ -3537,6 +3657,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a"
[[package]]
name = "windows_aarch64_msvc"
version = "0.39.0"
@ -3561,6 +3687,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1"
[[package]]
name = "windows_i686_gnu"
version = "0.39.0"
@ -3591,6 +3723,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c"
[[package]]
name = "windows_i686_msvc"
version = "0.39.0"
@ -3615,6 +3753,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d"
[[package]]
name = "windows_x86_64_gnu"
version = "0.39.0"
@ -3657,6 +3801,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.39.0"

View File

@ -11,9 +11,12 @@ edition = "2021"
tauri-build = { version = "1", features = [] }
[dependencies]
tauri = { version = "1", features = ["shell-open"] }
tauri = { version = "1", features = [ "path-all", "dialog-all", "shell-open"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
openssl = "0.10.66"
thiserror = "1.0.63"
chrono = "0.4.38"
[features]
# This feature is used for production builds or when a dev server is not specified, DO NOT REMOVE!!

View File

@ -1,15 +1,81 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
use openssl::{
asn1::Asn1Time,
pkey::PKey,
rsa::Rsa,
x509::{X509Builder, X509NameBuilder},
};
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
// create the error type that represents all errors possible in our program
#[derive(Debug, thiserror::Error)]
enum Error {
#[error(transparent)]
Io(#[from] std::io::Error),
#[error(transparent)]
ErrorStack(#[from] openssl::error::ErrorStack),
}
// we must manually implement serde::Serialize
impl serde::Serialize for Error {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
serializer.serialize_str(self.to_string().as_ref())
}
}
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
fn gen_rsa_pair(merchant_id: &str, email: &str, save_path: &str) -> Result<(), Error> {
println!("--- Begin ---");
// 生成 2048 位的 RSA 私钥
let rsa = Rsa::generate(2048)?;
// 创建私钥
let private_key = PKey::from_rsa(rsa)?;
let mut x509_name_builder = X509NameBuilder::new()?;
x509_name_builder.append_entry_by_text("CN", "PHIZ")?;
x509_name_builder.append_entry_by_text("O", merchant_id)?;
x509_name_builder.append_entry_by_text("OU", email)?;
let x509_name = x509_name_builder.build();
let mut x509_builder: X509Builder = X509Builder::new()?;
x509_builder.set_subject_name(&x509_name)?;
x509_builder.set_issuer_name(&x509_name)?;
x509_builder.set_pubkey(&private_key)?;
x509_builder.set_not_before(&Asn1Time::days_from_now(0).unwrap())?;
x509_builder.set_not_after(&Asn1Time::days_from_now(1095).unwrap())?;
x509_builder.sign(&private_key, openssl::hash::MessageDigest::sha256())?;
let x509 = x509_builder.build();
// 将私钥转换为 PEM 格式
let private_key_pem = private_key.private_key_to_pem_pkcs8()?;
// 保存私钥到文件
let private_key_path = PathBuf::from(format!("{}/{}_private_key.pem", save_path, merchant_id));
let mut private_key_file = File::create(&private_key_path)?;
private_key_file.write_all(&private_key_pem)?;
// // 将证书转换为 PEM 格式
let certificate_pem = x509.to_pem()?;
// 保存证书到文件
let certificate_path = format!("{}/{}_certificate.pem", save_path, merchant_id);
let mut certificate_file = File::create(&certificate_path)?;
certificate_file.write_all(&certificate_pem)?;
println!("--- Success ---");
Ok(())
}
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet])
.invoke_handler(tauri::generate_handler![gen_rsa_pair])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

View File

@ -6,7 +6,7 @@
"distDir": "../dist"
},
"package": {
"productName": "tauri-app",
"productName": "PhizPayTools",
"version": "0.1.0"
},
"tauri": {
@ -15,13 +15,24 @@
"shell": {
"all": false,
"open": true
},
"dialog": {
"all": true,
"ask": true,
"confirm": true,
"message": true,
"open": true,
"save": true
},
"path": {
"all": true
}
},
"windows": [
{
"title": "tauri-app",
"width": 800,
"height": 600
"title": "PhizPay Tools",
"width": 1280,
"height": 800
}
],
"security": {
@ -30,14 +41,8 @@
"bundle": {
"active": true,
"targets": "all",
"identifier": "com.tauri-app.app",
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
]
"identifier": "com.phiz.pay.tool",
"icon": ["icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico"]
}
}
}

View File

@ -1,25 +1,59 @@
<script setup lang="ts">
import { ref } from 'vue'
import { invoke } from '@tauri-apps/api/tauri'
import { message, open } from '@tauri-apps/api/dialog'
import { downloadDir } from '@tauri-apps/api/path'
const greetMsg = ref('')
const name = ref('')
const merchantId = ref('P80029767866')
const email = ref('zaeyee@163.com')
async function greet() {
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
greetMsg.value = await invoke('greet', { name: name.value })
async function genPrivateKey() {
try {
const savePath = await open({
title: 'Select a directory to save',
defaultPath: await downloadDir(),
directory: true,
recursive: true
})
if (!savePath) {
return message('Please select a directory to save')
}
await invoke('gen_rsa_pair', { merchantId: merchantId.value, email: email.value, savePath })
message('Successfully generated', 'Success')
} catch {
message('Generation failed', 'Error')
}
}
</script>
<template>
<div class="container text-center py-4">
<form class="flex justify-center" @submit.prevent="greet">
<input v-model="name" placeholder="Enter a name..." />
<button type="submit" class="ml-2">Greet</button>
</form>
<p class="mt-4">{{ greetMsg }}</p>
</div>
<form class="py-4 container w-100 mt-20" @submit.prevent="genPrivateKey">
<div for="merchantId">
<div class="mb-2">Merchant ID</div>
<input
v-model="merchantId"
id="merchantId"
placeholder="Enter your merchant id"
class="w-full px-3 py-2 rounded-lg bg-zinc-1 duration-300 focus:bg-zinc-2"
/>
</div>
<div for="Email" class="mt-4">
<div class="mb-2">Email</div>
<input
v-model="email"
placeholder="Enter your email"
class="w-full px-3 py-2 rounded-lg bg-zinc-1 duration-300 focus:bg-zinc-2"
/>
</div>
<div class="mt-4">
<button
type="submit"
class="w-full px-3 py-2 bg-primary c-white rounded-lg hover:op-80 active:op-100 duration-300"
>
Generate
</button>
</div>
</form>
</template>
<style scoped>
@ -39,32 +73,6 @@ async function greet() {
-webkit-text-size-adjust: 100%;
}
input,
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
color: #0f0f0f;
background-color: #ffffff;
transition: border-color 0.25s;
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
}
button {
cursor: pointer;
}
button:hover {
border-color: #396cd8;
}
button:active {
border-color: #396cd8;
background-color: #e8e8e8;
}
input,
button {
outline: none;

View File

@ -4,7 +4,10 @@ export default defineConfig({
shortcuts: {},
theme: {
colors: {
primary: 'var(--c-primary)'
primary: '#fe7716'
},
container: {
center: true
}
},
presets: [