feat(server):增加下发许可证功能。
This commit is contained in:
parent
2871ce94d0
commit
854d128b51
|
@ -34,3 +34,11 @@ pub async fn load_certificates(certificate_filename: &str) -> anyhow::Result<()>
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_public_key() -> &'static X509 {
|
||||
LICENSE_PUBKEY.get().unwrap()
|
||||
}
|
||||
|
||||
pub fn get_private_key() -> &'static PKey<Private> {
|
||||
LICENSE_PRIKEY.get().unwrap()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
use axum::{http::StatusCode, response::IntoResponse, routing, Json, Router};
|
||||
use base64::{engine::general_purpose::STANDARD, Engine as _};
|
||||
use openssl::{hash::MessageDigest, rsa::Padding, sign::Signer};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::vo::{self, LicenseRequestForm};
|
||||
|
||||
pub struct LicenseController {
|
||||
routes: Router,
|
||||
}
|
||||
|
||||
impl Into<Router> for LicenseController {
|
||||
fn into(self) -> Router {
|
||||
self.routes
|
||||
}
|
||||
}
|
||||
|
||||
impl LicenseController {
|
||||
pub fn init() -> Self {
|
||||
let routes = Router::new().route("/license", routing::post(issue_license));
|
||||
|
||||
Self { routes }
|
||||
}
|
||||
}
|
||||
|
||||
async fn issue_license(Json(request_form): Json<LicenseRequestForm>) -> impl IntoResponse {
|
||||
let mut license = vo::License::new(
|
||||
request_form.licensee_name,
|
||||
request_form.assignee_name,
|
||||
request_form.assignee_email,
|
||||
);
|
||||
for p in request_form.request_products.into_iter() {
|
||||
license.add_product(p, request_form.valid_days);
|
||||
}
|
||||
let serialized_license = license.serialize();
|
||||
|
||||
let private_key = crate::certificate::get_private_key();
|
||||
let mut signer = Signer::new(MessageDigest::sha1(), private_key).unwrap();
|
||||
signer.set_rsa_padding(Padding::PKCS1).unwrap();
|
||||
signer.update(serialized_license.as_bytes()).unwrap();
|
||||
|
||||
let cert = crate::certificate::get_public_key()
|
||||
.public_key()
|
||||
.unwrap()
|
||||
.public_key_to_der()
|
||||
.unwrap();
|
||||
|
||||
let base64_license = STANDARD.encode(serialized_license);
|
||||
let base64_signature = STANDARD.encode(signer.sign_to_vec().unwrap());
|
||||
let base64_cert = STANDARD.encode(cert);
|
||||
|
||||
let license_response = format!(
|
||||
"{}-{}-{}-{}",
|
||||
license.license_id, base64_license, base64_signature, base64_cert
|
||||
);
|
||||
|
||||
(StatusCode::OK, Json(json!({"license": license_response})))
|
||||
}
|
|
@ -5,7 +5,10 @@ use axum::Router;
|
|||
|
||||
/// 生成可迭代的转化为路由定义的控制器列表。
|
||||
pub fn controllers() -> Box<dyn Iterator<Item = Box<Router>>> {
|
||||
let controllers: Vec<Box<Router>> = vec![Box::new(products::ProductsController::init().into())];
|
||||
let controllers: Vec<Box<Router>> = vec![
|
||||
Box::new(products::ProductsController::init().into()),
|
||||
Box::new(license::LicenseController::init().into()),
|
||||
];
|
||||
|
||||
Box::from(controllers.into_iter())
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ pub fn empty_to_none<S: Into<String>>(s: S) -> Option<String> {
|
|||
|
||||
const RAND_LINCENSE_STR_SRC: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
|
||||
pub fn generate_product_license_id() -> String {
|
||||
pub fn generate_license_id() -> String {
|
||||
let choices = RAND_LINCENSE_STR_SRC.as_bytes();
|
||||
let mut rng = thread_rng();
|
||||
let mut code: Vec<String> = vec![];
|
||||
|
|
87
license_server/src/vo/license.rs
Normal file
87
license_server/src/vo/license.rs
Normal file
|
@ -0,0 +1,87 @@
|
|||
use chrono::{Duration, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::utils;
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Product {
|
||||
pub code: String,
|
||||
pub fallback_date: String,
|
||||
pub paid_up_to: String,
|
||||
pub extended: bool,
|
||||
}
|
||||
|
||||
impl Product {
|
||||
pub fn new<S: AsRef<str>>(code: S, authorize_days: i64) -> Self {
|
||||
let today = Utc::now().date_naive();
|
||||
let expires_date = (today + Duration::days(authorize_days))
|
||||
.format("%Y-%m-%d")
|
||||
.to_string();
|
||||
Self {
|
||||
code: code.as_ref().to_string(),
|
||||
fallback_date: expires_date.clone(),
|
||||
paid_up_to: expires_date,
|
||||
extended: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct License {
|
||||
pub license_id: String,
|
||||
pub licensee_name: String,
|
||||
pub assignee_name: String,
|
||||
pub assignee_email: String,
|
||||
pub license_restriction: String,
|
||||
pub check_concurrent_use: bool,
|
||||
pub products: Vec<Product>,
|
||||
#[serde(rename = "metadata")]
|
||||
pub meta_data: String,
|
||||
pub hash: String,
|
||||
pub grace_period_days: i32,
|
||||
pub auto_prolongated: bool,
|
||||
pub is_auto_prolongated: bool,
|
||||
}
|
||||
|
||||
impl License {
|
||||
pub fn new(
|
||||
licensee_name: String,
|
||||
assignee_name: String,
|
||||
assignee_email: Option<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
license_id: utils::generate_license_id(),
|
||||
licensee_name,
|
||||
assignee_name,
|
||||
assignee_email: assignee_email.unwrap_or(String::new()),
|
||||
license_restriction: String::new(),
|
||||
check_concurrent_use: false,
|
||||
products: vec![],
|
||||
meta_data: String::from("0120230102PPAA013009"),
|
||||
hash: String::from("41472961/0:1563609451"),
|
||||
grace_period_days: 7,
|
||||
auto_prolongated: true,
|
||||
is_auto_prolongated: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_product<S: AsRef<str>>(&mut self, product_code: S, valid_days: i64) {
|
||||
self.products.push(Product::new(product_code, valid_days));
|
||||
}
|
||||
|
||||
pub fn serialize(&self) -> String {
|
||||
serde_json::to_string(self).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LicenseRequestForm {
|
||||
pub licensee_name: String,
|
||||
pub assignee_name: String,
|
||||
pub assignee_email: Option<String>,
|
||||
pub valid_days: i64,
|
||||
pub request_products: Vec<String>,
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
mod license;
|
||||
mod shared;
|
||||
|
||||
pub use license::*;
|
||||
pub use shared::*;
|
||||
|
|
Loading…
Reference in New Issue
Block a user