定价统一:专业版包年 ¥99 / 永久 ¥199(与 OpsXShell 一致);授权真实链路验证
- /pricing 与落地页:¥299 终身→¥199 永久、¥69→¥99、个人版更名专业版(3/5 台设备); 补 Apipost 离线版式购买叙事(一机一码/当场发证/无需注册/年 2 次免费换绑) - 授权服务器(licence.rlwj.cn):opsxapi 永久计划 299→199;注册 opsxdb 产品与 trial/yearly/perpetual 计划——三产品公开 API 均为 0/99/199 - 真实链路验证:管理端签发 opsxapi 在线 LIC-(activate/verify 全通,Ed25519 签名下发)+ 离线 LICOFF-(绑本机 device_id);新增 4 项 Rust 单测用真实 fixture 跑通 (离线验签/换设备拒绝/篡改拒绝/在线响应签名)
This commit is contained in:
1 parent
c304b9f251
commit
0f8e1f75da
7 files changed
+57
-1
No files matched your search
Vendored
+1
-1
@@ -227,7 +227,7 @@
|
||||
<p class="sec-sub">先在工作台免费用起来,需要授权与服务时再付费。</p>
|
||||
<div class="pricing three">
|
||||
<div class="price-card">
|
||||
<div class="plan">个人版</div>
|
||||
<div class="plan">专业版</div>
|
||||
<div class="price"><b>¥99</b><span>/ 年</span></div>
|
||||
<div class="plan-sub">单设备授权 · 全功能</div>
|
||||
<ul>
|
||||
|
||||
@@ -432,3 +432,54 @@ pub fn deactivate(app: &AppHandle) -> Result<LicenseStatus, String> {
|
||||
let _ = fs::remove_file(&path);
|
||||
read_status(app)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use serde_json::json;
|
||||
|
||||
/// 真实服务器签发的离线证(licence.rlwj.cn,product=opsxapi)
|
||||
const REAL_OFFLINE: &str = include_str!("../../../tests/fixtures/licoff-opsxapi.txt");
|
||||
const REAL_DEVICE: &str = include_str!("../../../tests/fixtures/device-id.txt");
|
||||
|
||||
#[test]
|
||||
fn offline_serial_validates_for_bound_device() {
|
||||
let key = REAL_OFFLINE.trim();
|
||||
assert!(is_offline_license_key(key));
|
||||
let claims = verify_offline_serial(key, REAL_DEVICE.trim())
|
||||
.expect("真实离线证应通过本产品+设备校验");
|
||||
assert_eq!(claims.product_code, "opsxapi");
|
||||
assert!(claims.exp > claims.iat);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn offline_serial_rejects_other_device() {
|
||||
assert!(verify_offline_serial(REAL_OFFLINE.trim(), "00000000-0000-0000-0000-000000000000").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn offline_serial_rejects_tampered_payload() {
|
||||
// 篡改 base64 载荷中段一个字符(保持格式合法,签名必失效)
|
||||
let key = REAL_OFFLINE.trim().to_string();
|
||||
let (payload, sig) = key.strip_prefix("LICOFF-1.").unwrap().rsplit_once('.').unwrap();
|
||||
let mut chars: Vec<char> = payload.chars().collect();
|
||||
let mid = chars.len() / 2;
|
||||
chars[mid] = if chars[mid] == 'A' { 'B' } else { 'A' };
|
||||
let tampered = format!("LICOFF-1.{}.{}", chars.into_iter().collect::<String>(), sig);
|
||||
assert_ne!(key, tampered);
|
||||
assert!(verify_offline_serial(&tampered, REAL_DEVICE.trim()).is_err());
|
||||
}
|
||||
|
||||
/// 真实服务器 /v1/license/verify 响应的 Ed25519 签名(hex)与签名原文
|
||||
#[test]
|
||||
fn online_response_sig_verifies_with_embedded_key() {
|
||||
// 1) 原文直接验(证明公钥同源)
|
||||
let msg = include_str!("../../../tests/fixtures/verify-sig-msg.txt");
|
||||
let sig_hex = include_str!("../../../tests/fixtures/verify-sig.txt").trim();
|
||||
let sig = Signature::from_slice(&hex::decode(sig_hex).unwrap()).unwrap();
|
||||
offline_verifying_key().unwrap().verify(msg.as_bytes(), &sig).expect("服务器签名应通过内嵌公钥校验");
|
||||
// 2) 完整响应 JSON 走 verify_response_sig(证明客户端重组串与服务器一致)
|
||||
let payload: Value = serde_json::from_str(include_str!("../../../tests/fixtures/verify-response.json")).unwrap();
|
||||
assert!(verify_response_sig(&payload).is_ok());
|
||||
}
|
||||
}
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
b6eeb606-82ef-438f-946f-ea6fa6b272ec
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
LICOFF-1.eyJ2IjoxLCJwaWQiOiJvcHN4YXBpIiwiZGlkIjoiYjZlZWI2MDYtODJlZi00MzhmLTk0NmYtZWE2ZmE2YjI3MmVjIiwiZW1haWwiOiJsb2dhbkB0ZXN0LmRldiIsInB0IjoieWVhcmx5IiwiaWF0IjoxNzkyMDkyNzQwLCJleHAiOjE4MjM2Mjg3NDAsIm1kIjoxLCJjbiI6IkxvZ2FuKOa1i-ivlSkifQ.1G3TyluNJk1RB1S8vALMelhfUeb0S2YqqgoYYvSoq9JcAI64pMCoPNOUkbS0OOp-s4zIpEIxgHTSShbpsUxDCw
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"valid":true,"license_key":"LIC-2026-A424-9335-AA41-AD88","product_id":2,"product_name":"OpsxAPI","product_code":"opsxapi","features":["http","graphql","websocket","sse","socketio","mqtt","mock","testing","ai"],"status":"active","expires_at":"2027-10-16 03:31:21","days_left":364,"max_devices":3,"plan_type":"yearly","message":"验证成功","expires_at_unix":1823628681,"server_time":1792092713,"sig":"4d958e15f1ef10b3f2ea5f4fa2c6aae5f7f323145554ca9b64703ab0295dcacaee57cb02792c647e41eba62dc813ef515b040e644c06fac6c02a7707efe58c0b"}
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
v1|LIC-2026-A424-9335-AA41-AD88|true|active|1823628681|1792092713|false|3|yearly
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
4d958e15f1ef10b3f2ea5f4fa2c6aae5f7f323145554ca9b64703ab0295dcacaee57cb02792c647e41eba62dc813ef515b040e644c06fac6c02a7707efe58c0b
|
||||
Reference in new issue
Block a user