generate_license
This commit is contained in:
parent
f8ee182ea8
commit
6ee0e87f68
File diff suppressed because it is too large
Load Diff
17
Cargo.toml
17
Cargo.toml
|
@ -5,12 +5,9 @@ edition = "2021"
|
|||
|
||||
|
||||
|
||||
[dependencies.tokio]
|
||||
version = "1.35.1"
|
||||
features = ["full"]
|
||||
|
||||
[dependencies.axum]
|
||||
version = "0.7.4"
|
||||
[dependencies.actix-web]
|
||||
version = "4.4.1"
|
||||
|
||||
[dependencies.base64]
|
||||
version = "0.21.7"
|
||||
|
@ -32,9 +29,11 @@ features = ["derive"]
|
|||
version = "1.0.112"
|
||||
|
||||
|
||||
[dependencies.tower]
|
||||
version = "0.4.13"
|
||||
[dependencies.x509-parser]
|
||||
version = "0.15.1"
|
||||
|
||||
[dependencies.tower-http]
|
||||
version = "0.5.1"
|
||||
[dependencies.rand]
|
||||
version = "0.8.1"
|
||||
|
||||
[dependencies.mime]
|
||||
version= "0.3.17"
|
106
src/main.rs
106
src/main.rs
|
@ -1,55 +1,94 @@
|
|||
use std::error::Error;
|
||||
use axum::{
|
||||
routing::get,
|
||||
Router,
|
||||
response::Json,
|
||||
response::Html,
|
||||
};
|
||||
use axum::http::header;
|
||||
use axum::routing::post;
|
||||
|
||||
use actix_web::{App, HttpResponse, HttpServer, web};
|
||||
use base64::Engine;
|
||||
use base64::engine::general_purpose;
|
||||
use mime;
|
||||
use rand::Rng;
|
||||
use rsa::pkcs1::DecodeRsaPrivateKey;
|
||||
use rsa::pkcs1v15::SigningKey;
|
||||
use rsa::RsaPrivateKey;
|
||||
use rsa::signature::{SignatureEncoding, Signer};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{json, Value};
|
||||
use serde_json::json;
|
||||
use sha1::Sha1;
|
||||
use x509_parser::pem::parse_x509_pem;
|
||||
|
||||
const INDEX_HTML: &[u8] = include_bytes!("../assets/index.html");
|
||||
const ICONS: &[u8] = include_bytes!("../assets/images/icons.svg");
|
||||
|
||||
const CRT_PEM: &[u8] = include_bytes!("../jetbra.pem");
|
||||
const RSA_PRIVATE_KEY: &'static str = include_str!("../jetbra.key");
|
||||
|
||||
const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
|
||||
pub async fn generate_license(web::Json(mut license): web::Json<License>) -> Result<HttpResponse, Box<dyn Error>> {
|
||||
|
||||
// 1 generate license id
|
||||
let mut rng = rand::thread_rng();
|
||||
let license_id: String = (0..10)
|
||||
.map(|_| {
|
||||
let idx = rng.gen_range(0..CHARSET.len());
|
||||
CHARSET[idx] as char
|
||||
})
|
||||
.collect();
|
||||
license.license_id = Some(license_id.clone());
|
||||
|
||||
// 2 generate license_part_base64
|
||||
let license_part = serde_json::to_string(&license)?;
|
||||
let license_part_base64 = general_purpose::STANDARD.encode(license_part.as_bytes());
|
||||
|
||||
|
||||
// 3 generate sigResultsBase64
|
||||
let private_key = RsaPrivateKey::from_pkcs1_pem(RSA_PRIVATE_KEY)?;
|
||||
let signing_key = SigningKey::<Sha1>::new(private_key);
|
||||
let signature = signing_key.try_sign(license_part.as_bytes())?;
|
||||
let sig_results_base64 = general_purpose::STANDARD.encode(signature.to_bytes());
|
||||
|
||||
async fn generate_license(Json(payload): Json<License>) -> Json<Value> {
|
||||
dbg!(payload);
|
||||
Json(json!({ "data": 42 }))
|
||||
|
||||
// 4 generate cert base64
|
||||
let (_, pem) = parse_x509_pem(CRT_PEM)?;
|
||||
let cert_base64 = general_purpose::STANDARD.encode(pem.contents);
|
||||
|
||||
// 5 combine license
|
||||
let license = format!("{}-{}-{}-{}", license_id, license_part_base64, sig_results_base64, cert_base64);
|
||||
|
||||
Ok(HttpResponse::Ok().content_type(mime::APPLICATION_JSON).body(json!({"license": license}).to_string()))
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn Error>> {
|
||||
let app = Router::new()
|
||||
.route("/", get(|| async { Html(INDEX_HTML) }))
|
||||
.route("/images/icons.svg", get(|| async { ([(header::CONTENT_TYPE, "image/svg+xml")], ICONS) }))
|
||||
.route("/generateLicense", post(generate_license));
|
||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
|
||||
axum::serve(listener, app).await?;
|
||||
return Ok(());
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
HttpServer::new(|| {
|
||||
App::new()
|
||||
.route("/", web::get().to(|| async { HttpResponse::Ok().content_type(mime::TEXT_HTML_UTF_8).body(INDEX_HTML) }))
|
||||
.route("/index.html", web::get().to(|| async { HttpResponse::Ok().content_type(mime::TEXT_HTML_UTF_8).body(INDEX_HTML) }))
|
||||
.route("/images/icons.svg", web::get().to(|| async { HttpResponse::Ok().content_type(mime::IMAGE_SVG).body(ICONS) }))
|
||||
.route("/generateLicense", web::post().to(generate_license))
|
||||
})
|
||||
.bind(("127.0.0.1", 3000))?
|
||||
.run()
|
||||
.await
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct License {
|
||||
#[serde(rename = "licenseId")]
|
||||
license_id: Option<String>,
|
||||
|
||||
#[serde(default = "default_licensee_name")]
|
||||
#[serde(default = "default_licensee_name",rename = "licenseeName")]
|
||||
licensee_name: String,
|
||||
|
||||
#[serde(default = "default_empty_str")]
|
||||
#[serde(default = "default_empty_str",rename = "assigneeName")]
|
||||
assignee_name: String,
|
||||
|
||||
#[serde(default = "default_empty_str")]
|
||||
#[serde(default = "default_empty_str",rename = "assigneeEmail")]
|
||||
assignee_email: String,
|
||||
|
||||
#[serde(default = "default_empty_str")]
|
||||
#[serde(default = "default_empty_str",rename = "licenseRestriction")]
|
||||
license_restriction: String,
|
||||
|
||||
#[serde(default = "default_false")]
|
||||
#[serde(default = "default_false",rename = "checkConcurrentUse")]
|
||||
check_concurrent_use: bool,
|
||||
|
||||
products: Vec<Product>,
|
||||
|
@ -60,22 +99,22 @@ pub struct License {
|
|||
#[serde(default = "default_hash")]
|
||||
hash: String,
|
||||
|
||||
#[serde(default = "default_grace_period_days")]
|
||||
#[serde(default = "default_grace_period_days",rename = "gracePeriodDays")]
|
||||
grace_period_days: i32,
|
||||
|
||||
#[serde(default = "default_true")]
|
||||
#[serde(default = "default_true",rename = "autoProlongated")]
|
||||
auto_prolongated: bool,
|
||||
|
||||
#[serde(default = "default_true")]
|
||||
#[serde(default = "default_true",rename = "isAutoProlongated")]
|
||||
is_auto_prolongated: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Product {
|
||||
code: String,
|
||||
#[serde(default = "default_expire_date")]
|
||||
#[serde(default = "default_expire_date",rename = "fallbackDate")]
|
||||
fallback_date: String,
|
||||
#[serde(default = "default_expire_date")]
|
||||
#[serde(default = "default_expire_date",rename = "paidUpTo")]
|
||||
paid_up_to: String,
|
||||
#[serde(default = "default_true")]
|
||||
extended: bool,
|
||||
|
@ -85,6 +124,7 @@ pub struct Product {
|
|||
fn default_licensee_name() -> String {
|
||||
String::from("for test only")
|
||||
}
|
||||
|
||||
fn default_empty_str() -> String {
|
||||
String::from("")
|
||||
}
|
||||
|
@ -110,5 +150,5 @@ fn default_grace_period_days() -> i32 {
|
|||
}
|
||||
|
||||
fn default_expire_date() -> String {
|
||||
"2023-12-31".into()
|
||||
"2030-12-31".into()
|
||||
}
|
Loading…
Reference in New Issue