feat: 生成PhizPay私钥和证书功能
parent
203881c5b2
commit
5848155bba
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "tauri-app",
|
||||
"name": "phiz-pay-tools",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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!!
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
86
src/App.vue
86
src/App.vue
|
@ -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;
|
||||
|
|
|
@ -4,7 +4,10 @@ export default defineConfig({
|
|||
shortcuts: {},
|
||||
theme: {
|
||||
colors: {
|
||||
primary: 'var(--c-primary)'
|
||||
primary: '#fe7716'
|
||||
},
|
||||
container: {
|
||||
center: true
|
||||
}
|
||||
},
|
||||
presets: [
|
||||
|
|
Loading…
Reference in New Issue