feat: v0.1.1
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "script-sign"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
edition = "2021"
|
||||
authors = ["Hatter Jiang <jht5945@gmail.com>"]
|
||||
description = "Script Sign"
|
||||
|
||||
@@ -1,25 +1,35 @@
|
||||
use rust_util::XResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct KeyMeta {
|
||||
pub public_key_point_hex: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct KeyMap {
|
||||
key_map: HashMap<String, String>,
|
||||
pub key_map: HashMap<String, KeyMeta>,
|
||||
}
|
||||
|
||||
impl KeyMap {
|
||||
pub fn system() -> XResult<Self> {
|
||||
pub fn system() -> Self {
|
||||
let signing_keys = r##"
|
||||
{
|
||||
"yk-r1": "04dd3eebd906c9cf00b08ec29f7ed61804d1cc1d1352d9257b628191e08fc3717c4fae3298cd5c4829cec8bf3a946e7db60b7857e1287f6a0bae6b3f2342f007d0"
|
||||
"yk-r1": {
|
||||
"public_key_point_hex": "04dd3eebd906c9cf00b08ec29f7ed61804d1cc1d1352d9257b628191e08fc3717c4fae3298cd5c4829cec8bf3a946e7db60b7857e1287f6a0bae6b3f2342f007d0"
|
||||
}
|
||||
}
|
||||
"##;
|
||||
// unwrap should not happen
|
||||
let key_map: HashMap<String, String> = serde_json::from_str(signing_keys).unwrap();
|
||||
Ok(KeyMap { key_map })
|
||||
let key_map: HashMap<String, KeyMeta> = serde_json::from_str(signing_keys).unwrap();
|
||||
KeyMap { key_map }
|
||||
}
|
||||
|
||||
pub fn find(&self, key_id: &str) -> Option<&String> {
|
||||
pub fn from(key_map: HashMap<String, KeyMeta>) -> Self {
|
||||
Self { key_map }
|
||||
}
|
||||
|
||||
pub fn find(&self, key_id: &str) -> Option<&KeyMeta> {
|
||||
self.key_map.get(key_id)
|
||||
}
|
||||
}
|
||||
|
||||
125
src/lib.rs
125
src/lib.rs
@@ -22,7 +22,7 @@ pub struct Script {
|
||||
|
||||
impl Script {
|
||||
pub fn verify_script_file_with_system_key_map(script_file: &str) -> XResult<bool> {
|
||||
Self::verify_script_file(script_file, &KeyMap::system()?)
|
||||
Self::verify_script_file(script_file, &KeyMap::system())
|
||||
}
|
||||
|
||||
pub fn verify_script_file(script_file: &str, key_map: &KeyMap) -> XResult<bool> {
|
||||
@@ -42,29 +42,60 @@ impl Script {
|
||||
|
||||
pub fn parse(script: &str) -> XResult<Script> {
|
||||
let lines = script.lines().collect::<Vec<_>>();
|
||||
let last_non_empty_line = lines.iter().rev().find(|ln| !ln.is_empty());
|
||||
match last_non_empty_line {
|
||||
Some(last_non_empty_line) if last_non_empty_line.starts_with(SIGNATURE_PREFIX) => {
|
||||
let script_signature = ScriptSignature::parse(last_non_empty_line)?;
|
||||
let final_lines = lines
|
||||
.iter()
|
||||
.rev()
|
||||
.skip_while(|ln| ln.is_empty())
|
||||
.skip(1)
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
.rev()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut in_signature_section = false;
|
||||
let mut signature_lines = vec![];
|
||||
let mut content_lines = vec![];
|
||||
let mut signature_line = String::new();
|
||||
|
||||
let mut push_signature_line = |signature_line: &mut String| {
|
||||
if !signature_line.is_empty() {
|
||||
signature_lines.push(signature_line.clone());
|
||||
signature_line.clear();
|
||||
}
|
||||
};
|
||||
|
||||
for line in &lines {
|
||||
if in_signature_section {
|
||||
if line.starts_with(SIGNATURE_PREFIX) {
|
||||
push_signature_line(&mut signature_line);
|
||||
signature_line.push_str(line);
|
||||
} else if line.starts_with("//") {
|
||||
signature_line.push_str(line.chars().skip(2).collect::<String>().trim());
|
||||
} else if !line.trim().is_empty() {
|
||||
return simple_error!("Bad signature section line, find: '{line}'");
|
||||
}
|
||||
} else {
|
||||
if line.starts_with(SIGNATURE_PREFIX) {
|
||||
in_signature_section = true;
|
||||
push_signature_line(&mut signature_line);
|
||||
signature_line.push_str(line);
|
||||
} else {
|
||||
content_lines.push(line.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
push_signature_line(&mut signature_line);
|
||||
|
||||
if signature_lines.len() > 1 {
|
||||
return simple_error!(
|
||||
"Found {} signatures, only supports one signature.",
|
||||
signature_lines.len()
|
||||
);
|
||||
}
|
||||
|
||||
if signature_lines.is_empty() {
|
||||
Ok(Script {
|
||||
content_lines: final_lines.iter().map(ToString::to_string).collect(),
|
||||
content_lines,
|
||||
signature: None,
|
||||
})
|
||||
} else {
|
||||
let script_signature = ScriptSignature::parse(&signature_lines[0])?;
|
||||
Ok(Script {
|
||||
content_lines,
|
||||
signature: Some(script_signature),
|
||||
})
|
||||
}
|
||||
_ => Ok(Script {
|
||||
content_lines: lines.iter().map(ToString::to_string).collect(),
|
||||
signature: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_string(&self) -> String {
|
||||
@@ -79,8 +110,13 @@ impl Script {
|
||||
} else {
|
||||
joined_content_liens.push_str("\n\n");
|
||||
}
|
||||
joined_content_liens.push_str(&signature.as_string());
|
||||
let signature_lines = signature.as_string_lines_default_width();
|
||||
for signature_line in &signature_lines {
|
||||
joined_content_liens.push_str(&signature_line);
|
||||
joined_content_liens.push('\n');
|
||||
}
|
||||
// joined_content_liens.push_str(&signature.as_string());
|
||||
// joined_content_liens.push('\n');
|
||||
joined_content_liens
|
||||
}
|
||||
}
|
||||
@@ -99,7 +135,7 @@ impl Script {
|
||||
None => return simple_error!("Sign key id: {} not found", &signature.key_id),
|
||||
Some(key) => key,
|
||||
};
|
||||
let key_bytes = hex::decode(key)?;
|
||||
let key_bytes = hex::decode(&key.public_key_point_hex)?;
|
||||
let digest_sha256 = self.normalize_content_lines_and_sha256(&signature.time);
|
||||
match signature.algorithm {
|
||||
ScriptSignatureAlgorithm::ES256 => {
|
||||
@@ -203,3 +239,48 @@ fn test_script_parse_02() {
|
||||
assert_eq!("2025-01-05T20:57:14+08:00", s.time);
|
||||
assert_eq!(b"helloworld".to_vec(), s.signature);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_parse_03() {
|
||||
let script =
|
||||
Script::parse(r##"#!/usr/bin/env -S deno run --allow-env
|
||||
|
||||
console.log("Hello world.");
|
||||
|
||||
// @SCRIPT-SIGNATURE-V1: yk-r1.ES256.20250122T233410+08:00.MEQCIGogDudoVpCVfGiNPu8Wn6YPDtFX5OXC4bKtsN1nw414AiAq+5EVdvOuKAlXdVeeE1d91mKX9TaSTR25jliUx0km6A=="##)
|
||||
.unwrap();
|
||||
assert!(script.verify(&KeyMap::system()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_parse_04() {
|
||||
let script =
|
||||
Script::parse(r##"#!/usr/bin/env -S deno run --allow-env
|
||||
|
||||
console.log("Hello world.");
|
||||
|
||||
// @SCRIPT-SIGNATURE-V1: yk-r1.ES256.20250122T233410+08:00.MEQCIGogDudoVpCVfGiNPu8Wn6YPDtFX5OXC4bKtsN1nw414AiAq+5EVdvOuKAlXdVeeE1d91mKX9TaSTR25jliUx0km6A=="##)
|
||||
.unwrap();
|
||||
let script_str = script.as_string();
|
||||
assert_eq!(r##"#!/usr/bin/env -S deno run --allow-env
|
||||
|
||||
console.log("Hello world.");
|
||||
|
||||
// @SCRIPT-SIGNATURE-V1: yk-r1.ES256.20250122T233410+08:00.MEQCIGogDudoVpCVfGiNPu8W
|
||||
// n6YPDtFX5OXC4bKtsN1nw414AiAq+5EVdvOuKAlXdVeeE1d91mKX9TaSTR25jliUx0km6A==
|
||||
"##, script_str);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_parse_05() {
|
||||
let script = Script::parse(
|
||||
r##"#!/usr/bin/env -S deno run --allow-env
|
||||
|
||||
console.log("Hello world.");
|
||||
|
||||
// @SCRIPT-SIGNATURE-V1: yk-r1.ES256.20250122T233410+08:00.MEQCIGogDudoVpCVfGiNPu
|
||||
// 8Wn6YPDtFX5OXC4bKtsN1nw414AiAq+5EVdvOuKAlXdVeeE1d91mKX9TaSTR25jliUx0km6A=="##,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(script.verify(&KeyMap::system()).unwrap());
|
||||
}
|
||||
|
||||
@@ -79,6 +79,21 @@ impl ScriptSignature {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn as_string_lines_default_width(&self) -> Vec<String> {
|
||||
self.as_string_lines(80)
|
||||
}
|
||||
|
||||
pub fn as_string_lines(&self, width: usize) -> Vec<String> {
|
||||
let mut lines = vec![];
|
||||
let str = self.as_string();
|
||||
let chars = str.chars().skip(3).collect::<Vec<_>>();
|
||||
let chunks = chars.chunks(width);
|
||||
for chunk in chunks {
|
||||
lines.push(format!("// {}", chunk.iter().collect::<String>()));
|
||||
}
|
||||
lines
|
||||
}
|
||||
|
||||
pub fn as_string(&self) -> String {
|
||||
let mut s = String::with_capacity(245);
|
||||
s.push_str(SIGNATURE_PREFIX);
|
||||
|
||||
Reference in New Issue
Block a user