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]
|
[dependencies.actix-web]
|
||||||
version = "0.7.4"
|
version = "4.4.1"
|
||||||
|
|
||||||
[dependencies.base64]
|
[dependencies.base64]
|
||||||
version = "0.21.7"
|
version = "0.21.7"
|
||||||
|
@ -32,9 +29,11 @@ features = ["derive"]
|
||||||
version = "1.0.112"
|
version = "1.0.112"
|
||||||
|
|
||||||
|
|
||||||
[dependencies.tower]
|
[dependencies.x509-parser]
|
||||||
version = "0.4.13"
|
version = "0.15.1"
|
||||||
|
|
||||||
[dependencies.tower-http]
|
[dependencies.rand]
|
||||||
version = "0.5.1"
|
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 std::error::Error;
|
||||||
use axum::{
|
|
||||||
routing::get,
|
use actix_web::{App, HttpResponse, HttpServer, web};
|
||||||
Router,
|
use base64::Engine;
|
||||||
response::Json,
|
use base64::engine::general_purpose;
|
||||||
response::Html,
|
use mime;
|
||||||
};
|
use rand::Rng;
|
||||||
use axum::http::header;
|
use rsa::pkcs1::DecodeRsaPrivateKey;
|
||||||
use axum::routing::post;
|
use rsa::pkcs1v15::SigningKey;
|
||||||
|
use rsa::RsaPrivateKey;
|
||||||
|
use rsa::signature::{SignatureEncoding, Signer};
|
||||||
use serde::{Deserialize, Serialize};
|
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 INDEX_HTML: &[u8] = include_bytes!("../assets/index.html");
|
||||||
const ICONS: &[u8] = include_bytes!("../assets/images/icons.svg");
|
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);
|
// 4 generate cert base64
|
||||||
Json(json!({ "data": 42 }))
|
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]
|
#[actix_web::main]
|
||||||
async fn main() -> Result<(), Box<dyn Error>> {
|
async fn main() -> std::io::Result<()> {
|
||||||
let app = Router::new()
|
HttpServer::new(|| {
|
||||||
.route("/", get(|| async { Html(INDEX_HTML) }))
|
App::new()
|
||||||
.route("/images/icons.svg", get(|| async { ([(header::CONTENT_TYPE, "image/svg+xml")], ICONS) }))
|
.route("/", web::get().to(|| async { HttpResponse::Ok().content_type(mime::TEXT_HTML_UTF_8).body(INDEX_HTML) }))
|
||||||
.route("/generateLicense", post(generate_license));
|
.route("/index.html", web::get().to(|| async { HttpResponse::Ok().content_type(mime::TEXT_HTML_UTF_8).body(INDEX_HTML) }))
|
||||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
|
.route("/images/icons.svg", web::get().to(|| async { HttpResponse::Ok().content_type(mime::IMAGE_SVG).body(ICONS) }))
|
||||||
axum::serve(listener, app).await?;
|
.route("/generateLicense", web::post().to(generate_license))
|
||||||
return Ok(());
|
})
|
||||||
|
.bind(("127.0.0.1", 3000))?
|
||||||
|
.run()
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct License {
|
pub struct License {
|
||||||
|
#[serde(rename = "licenseId")]
|
||||||
license_id: Option<String>,
|
license_id: Option<String>,
|
||||||
|
|
||||||
#[serde(default = "default_licensee_name")]
|
#[serde(default = "default_licensee_name",rename = "licenseeName")]
|
||||||
licensee_name: String,
|
licensee_name: String,
|
||||||
|
|
||||||
#[serde(default = "default_empty_str")]
|
#[serde(default = "default_empty_str",rename = "assigneeName")]
|
||||||
assignee_name: String,
|
assignee_name: String,
|
||||||
|
|
||||||
#[serde(default = "default_empty_str")]
|
#[serde(default = "default_empty_str",rename = "assigneeEmail")]
|
||||||
assignee_email: String,
|
assignee_email: String,
|
||||||
|
|
||||||
#[serde(default = "default_empty_str")]
|
#[serde(default = "default_empty_str",rename = "licenseRestriction")]
|
||||||
license_restriction: String,
|
license_restriction: String,
|
||||||
|
|
||||||
#[serde(default = "default_false")]
|
#[serde(default = "default_false",rename = "checkConcurrentUse")]
|
||||||
check_concurrent_use: bool,
|
check_concurrent_use: bool,
|
||||||
|
|
||||||
products: Vec<Product>,
|
products: Vec<Product>,
|
||||||
|
@ -60,22 +99,22 @@ pub struct License {
|
||||||
#[serde(default = "default_hash")]
|
#[serde(default = "default_hash")]
|
||||||
hash: String,
|
hash: String,
|
||||||
|
|
||||||
#[serde(default = "default_grace_period_days")]
|
#[serde(default = "default_grace_period_days",rename = "gracePeriodDays")]
|
||||||
grace_period_days: i32,
|
grace_period_days: i32,
|
||||||
|
|
||||||
#[serde(default = "default_true")]
|
#[serde(default = "default_true",rename = "autoProlongated")]
|
||||||
auto_prolongated: bool,
|
auto_prolongated: bool,
|
||||||
|
|
||||||
#[serde(default = "default_true")]
|
#[serde(default = "default_true",rename = "isAutoProlongated")]
|
||||||
is_auto_prolongated: bool,
|
is_auto_prolongated: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct Product {
|
pub struct Product {
|
||||||
code: String,
|
code: String,
|
||||||
#[serde(default = "default_expire_date")]
|
#[serde(default = "default_expire_date",rename = "fallbackDate")]
|
||||||
fallback_date: String,
|
fallback_date: String,
|
||||||
#[serde(default = "default_expire_date")]
|
#[serde(default = "default_expire_date",rename = "paidUpTo")]
|
||||||
paid_up_to: String,
|
paid_up_to: String,
|
||||||
#[serde(default = "default_true")]
|
#[serde(default = "default_true")]
|
||||||
extended: bool,
|
extended: bool,
|
||||||
|
@ -85,6 +124,7 @@ pub struct Product {
|
||||||
fn default_licensee_name() -> String {
|
fn default_licensee_name() -> String {
|
||||||
String::from("for test only")
|
String::from("for test only")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_empty_str() -> String {
|
fn default_empty_str() -> String {
|
||||||
String::from("")
|
String::from("")
|
||||||
}
|
}
|
||||||
|
@ -110,5 +150,5 @@ fn default_grace_period_days() -> i32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_expire_date() -> String {
|
fn default_expire_date() -> String {
|
||||||
"2023-12-31".into()
|
"2030-12-31".into()
|
||||||
}
|
}
|
Loading…
Reference in New Issue