Compare commits

...

2 Commits

Author SHA1 Message Date
polwex
b4aaea6598 login lib -> signer lib 2025-03-20 01:11:49 +07:00
polwex
50d5f9f387 adapted to changes in signer lib 2025-03-20 01:11:20 +07:00
20 changed files with 895 additions and 561 deletions

View File

@ -29,6 +29,15 @@ wit_bindgen::generate!({
additional_derives: [PartialEq, serde::Deserialize, serde::Serialize, process_macros::SerdeJsonInto],
});
#[derive(Debug, Serialize, Deserialize)]
enum SignerRequest {
Sign,
Verify { node: String, signature: Vec<u8> },
}
#[derive(Debug, Serialize, Deserialize, SerdeJsonInto)]
struct SignResponse {
signature: Vec<u8>,
}
#[derive(Debug, Serialize, Deserialize)]
enum FrontendRequest {
Sign,
@ -37,22 +46,11 @@ enum FrontendRequest {
Debug(String),
}
#[derive(Debug, Serialize, Deserialize)]
enum SignerRequest {
Sign(SignRequest),
Verify { from: Address, data: SignResponse },
}
#[derive(Debug, Serialize, Deserialize)]
struct SignRequest {
struct LoginMessage {
pub site: String,
pub time: u64,
pub nonce: Option<String>,
}
#[derive(Debug, Serialize, Deserialize, SerdeJsonInto)]
struct SignResponse {
pub body: SignRequest,
pub message: Vec<u8>,
pub signature: Vec<u8>,
}
const ICON: &str = include_str!("icon");
#[derive(Debug, Serialize, Deserialize)]
@ -94,6 +92,35 @@ impl VersionedState {
}
}
fn _signer_test(our: &Address) -> anyhow::Result<()> {
let target = Address::new(our.node(), ("sign", "sign", "sys"));
let login_message = LoginMessage {
site: WEB2_URL.to_string(),
nonce: Some(WEB2_LOGIN_NONCE.to_string()),
time: get_now(),
};
let blob = serde_json::to_vec(&login_message)?;
// Get the signature from login:sys:sys
let res: SignResponse = Request::to(target.clone())
.blob_bytes(blob.clone())
.body(serde_json::to_vec(&SignerRequest::Sign)?)
.send_and_await_response(10)??
.body()
.try_into()?;
// Send signature to designated endpoint on Web2 app
let body2 = SignerRequest::Verify {
node: our.node().to_string(),
signature: res.signature,
};
let verify_res = Request::to(target)
.blob_bytes(blob)
.body(serde_json::to_vec(&body2)?)
.send_and_await_response(10)??;
let is_good: bool = serde_json::from_slice(verify_res.body())?;
kiprintln!("verify_res \n{:#?}", is_good);
Ok(())
}
call_init!(initialize);
fn initialize(our: Address) {
init_logging(Level::DEBUG, Level::INFO, None, None, None).unwrap();
@ -115,12 +142,6 @@ fn initialize(our: Address) {
http_server
.bind_ws_path("/", WsBindingConfig::default())
.unwrap();
// let http_config = HttpBindingConfig::default().secure_subdomain(true);
// http_server
// .serve_ui("ui", vec!["/hypr-login"], http_config.clone())
// .expect("Failed to serve UI");
// http_server.secure_bind_http_path("/").unwrap();
main_loop(&our, &mut state, &mut http_server);
}
@ -207,15 +228,17 @@ fn handle_login_request(
let request = serde_json::from_slice::<FrontendRequest>(request_bytes)?;
match request {
FrontendRequest::Sign => {
let target = Address::new(our.node(), ("login", "login", "sys"));
let lr = SignerRequest::Sign(SignRequest {
let target = Address::new(our.node(), ("sign", "sign", "sys"));
let body = LoginMessage {
site: WEB2_URL.to_string(),
nonce: Some(WEB2_LOGIN_NONCE.to_string()),
time: get_now(),
});
};
let body_bytes = serde_json::to_vec(&body)?;
// Get the signature from login:sys:sys
let res: SignResponse = Request::to(target)
.body(serde_json::to_vec(&lr)?)
.blob_bytes(body_bytes)
.body(serde_json::to_vec(&SignerRequest::Sign)?)
.send_and_await_response(10)??
.body()
.try_into()?;
@ -255,7 +278,8 @@ fn attempt_login(
let mut json_headers = HashMap::new();
json_headers.insert("Content-type".to_string(), "application/json".to_string());
let node = our.node();
let message = signature_response.message;
let blob = get_blob().ok_or(anyhow::anyhow!("no blob"))?;
let message = blob.bytes();
let signature = signature_response.signature;
let json =
serde_json::to_vec(&json!({"node":node, "message": message, "signature": signature}))?;

View File

@ -227,6 +227,7 @@ fn mother_script(prefix: &str) -> String {
<script>
const HYPERWARE_APP_PATH = '{0}';
</script>
<script src="./proxy.js" />
"#,
prefix
);

Binary file not shown.

Binary file not shown.

View File

@ -8,14 +8,14 @@
"homepage:homepage:sys",
"http-server:distro:sys",
"http-client:distro:sys",
"login:login:sys",
"sign:sign:sys",
"vfs:distro:sys"
],
"grant_capabilities": [
"homepage:homepage:sys",
"http-server:distro:sys",
"http-client:distro:sys",
"login:login:sys",
"sign:sign:sys",
"vfs:distro:sys"
],
"public": false

View File

@ -1,6 +0,0 @@
interface all {}
world login-sys-v0 {
import all;
include process-v1;
}

View File

@ -1,165 +0,0 @@
use crate::hyperware::process;
use anyhow::{anyhow, Result};
use hyperware::process::standard::send_response;
use hyperware_process_lib::net::{NetAction, NetResponse};
use hyperware_process_lib::{
await_message, call_init, eth, get_blob, get_typed_state, homepage, http, hypermap, kiprintln,
set_state, Address, Capability, LazyLoadBlob, Message, NodeId, Request, Response,
};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::str::FromStr;
wit_bindgen::generate!({
path: "target/wit",
world: "login-sys-v0",
generate_unused_types: true,
additional_derives: [PartialEq, serde::Deserialize, serde::Serialize, process_macros::SerdeJsonInto],
});
#[derive(Debug, Serialize, Deserialize)]
struct LoginStateV1 {
our: Address,
apps: HashMap<NodeId, String>,
}
#[derive(Debug, Serialize, Deserialize)]
enum LoginRequest {
Sign(SignRequest),
Verify { from: Address, data: SignResponse },
}
#[derive(Debug, Serialize, Deserialize)]
struct SignRequest {
pub site: String,
pub time: u64,
pub nonce: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
struct SignResponse {
pub body: SignRequest,
pub message: Vec<u8>,
pub signature: Vec<u8>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "version")]
enum VersionedState {
/// State fully stored in memory, persisted using serde_json.
/// Future state version will use SQLite.
V1(LoginStateV1),
}
impl VersionedState {
fn load(our: Address) -> Self {
get_typed_state(|bytes| serde_json::from_slice(bytes)).unwrap_or(Self::V1(LoginStateV1 {
our,
apps: HashMap::new(),
}))
}
fn save(&self) {
set_state(&serde_json::to_vec(&self).expect("Failed to serialize contacts state!"));
}
}
call_init!(initialize);
fn initialize(our: Address) {
let mut state = VersionedState::load(our.clone());
loop {
let msg = await_message();
match msg {
Err(_send_error) => {
// ignore send errors, local-only process
continue;
}
Ok(Message::Request {
source,
body,
capabilities,
..
}) => {
handle_request(&our, &source, &mut state, &body, capabilities).unwrap_or_default()
}
_ => continue, // ignore responses
}
}
}
fn handle_request(
our: &Address,
source: &Address,
state: &mut VersionedState,
request_bytes: &[u8],
capabilities: Vec<Capability>,
) -> Result<()> {
let req = serde_json::from_slice::<LoginRequest>(request_bytes)?;
match req {
LoginRequest::Sign(r) => handle_sign(our, r, request_bytes),
LoginRequest::Verify { from, data } => handle_verify(from, data),
}
}
// let message = [
// from.to_string().as_bytes(),
// &km.lazy_load_blob
// .as_ref()
// .unwrap_or(&lib::core::LazyLoadBlob {
// mime: None,
// bytes: vec![],
// })
// .bytes,
// ]
// .concat();
// pub fn validate_signature(from: &str, signature: &[u8], message: &[u8], pki: &OnchainPKI) -> bool {
// if let Some(peer_id) = pki.get(from) {
// let their_networking_key = signature::UnparsedPublicKey::new(
// &signature::ED25519,
// net_key_string_to_hex(&peer_id.networking_key),
// );
// their_networking_key.verify(message, signature).is_ok()
// } else {
// false
// }
// }
fn handle_sign(our: &Address, req: SignRequest, request_bytes: &[u8]) -> Result<()> {
let body = rmp_serde::to_vec(&NetAction::Sign)?;
let res = Request::to(("our", "net", "distro", "sys"))
.blob_bytes(request_bytes)
.body(body)
.send_and_await_response(10)??;
let Ok(NetResponse::Signed) = rmp_serde::from_slice::<NetResponse>(res.body()) else {
return Err(anyhow!("signature failed"));
};
let newblob = res.blob();
let message = [our.to_string().as_bytes(), request_bytes].concat();
match newblob {
None => Err(anyhow!("no blob")),
Some(b) => {
let lr = SignResponse {
body: req,
message,
signature: b.bytes().to_vec(),
};
let lrj = serde_json::to_vec(&lr)?;
Response::new().body(lrj).send()?;
Ok(())
}
}
}
fn handle_verify(from: Address, data: SignResponse) -> Result<()> {
let signature = data.signature;
let body = rmp_serde::to_vec(&NetAction::Verify { from, signature })?;
let req_bytes = rmp_serde::to_vec(&data.body)?;
let res = Request::to(("our", "net", "distro", "sys"))
.blob_bytes(req_bytes)
.body(body)
.send_and_await_response(10)??;
let resp = rmp_serde::from_slice::<NetResponse>(res.body())?;
match resp {
NetResponse::Verified(is_good) => {
Response::new().body(serde_json::to_vec(&is_good)?).send()?;
Ok(())
}
_ => Err(anyhow!("weird response")),
}
}

Binary file not shown.

Binary file not shown.

View File

@ -1,11 +0,0 @@
[
{
"process_name": "login",
"process_wasm_path": "/login.wasm",
"on_exit": "Restart",
"request_networking": false,
"request_capabilities": ["net:distro:sys"],
"grant_capabilities": ["net:distro:sys"],
"public": false
}
]

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
[workspace]
resolver = "2"
members = [
"login",
"sign",
]
[profile.release]

View File

@ -0,0 +1,23 @@
interface sign{
use standard.{address};
// takes blob for message to sign or verify
variant request{
sign,
verify(verify-request)
}
// takes blob
record verify-request{
node: string,
signature: list<u8>
}
// takes blob
record sign-response{
signature: list<u8>
}
}
world sign-sys-v0 {
import sign;
include process-v1;
}

View File

@ -1,9 +1,9 @@
{
"name": "Login",
"description": "Login with Hyperware",
"name": "Sign",
"description": "Sign messages with Hyperware",
"image": "",
"properties": {
"package_name": "login",
"package_name": "sign",
"current_version": "1.0.0",
"publisher": "sys",
"mirrors": [],

BIN
signer/pkg/api.zip Normal file

Binary file not shown.

11
signer/pkg/manifest.json Normal file
View File

@ -0,0 +1,11 @@
[
{
"process_name": "sign",
"process_wasm_path": "/sign.wasm",
"on_exit": "Restart",
"request_networking": false,
"request_capabilities": ["net:distro:sys", "vfs:distro:sys"],
"grant_capabilities": ["net:distro:sys", "vfs:distro:sys"],
"public": false
}
]

BIN
signer/pkg/sign.wasm Normal file

Binary file not shown.

View File

@ -1,5 +1,5 @@
[package]
name = "login"
name = "sign"
version = "0.1.0"
edition = "2021"
@ -8,7 +8,7 @@ simulation-mode = []
[dependencies]
anyhow = "1.0.97"
hyperware_process_lib = "1.0.3"
hyperware_process_lib = {version = "1.0.4", features = ["logging"]}
process_macros = "0.1"
rmp-serde = "1.3.0"
serde = { version = "1.0", features = ["derive"] }

98
signer/sign/src/lib.rs Normal file
View File

@ -0,0 +1,98 @@
use crate::hyperware::process::sign;
use anyhow::{anyhow, Result};
use hyperware_process_lib::logging::{error, init_logging, Level};
use hyperware_process_lib::net::{NetAction, NetResponse};
use hyperware_process_lib::{
await_message, call_init, get_blob, kiprintln, Address, Message, Request, Response,
};
wit_bindgen::generate!({
path: "target/wit",
world: "sign-sys-v0",
generate_unused_types: true,
additional_derives: [PartialEq, serde::Deserialize, serde::Serialize, process_macros::SerdeJsonInto],
});
call_init!(initialize);
fn initialize(our: Address) {
// this seems to require calling vfs:distro:sys
init_logging(Level::DEBUG, Level::INFO, None, None, None).unwrap();
loop {
match await_message() {
Err(send_error) => error!("got SendError: {send_error}"),
Ok(ref message) => {
match message {
Message::Request { body, .. } => match handle_request(&our, &body) {
Ok(_) => continue,
Err(request_error) => {
error!("error handling sign request: \n{request_error}")
}
},
_ => error!("Response received at sign process"), // we are awaiting all requests no resposes should be received
}
}
}
}
}
fn handle_request(our: &Address, request_bytes: &[u8]) -> Result<()> {
match request_bytes.try_into()? {
sign::Request::Sign => handle_sign(),
sign::Request::Verify(req) => handle_verify(our, req),
}
}
fn handle_sign() -> Result<()> {
let Some(blob) = get_blob() else {
return Err(anyhow!("no blob"));
};
let body = rmp_serde::to_vec(&NetAction::Sign)?;
let res = Request::to(("our", "net", "distro", "sys"))
.blob(blob.clone())
.body(body)
.send_and_await_response(10)??;
let Ok(NetResponse::Signed) = rmp_serde::from_slice::<NetResponse>(res.body()) else {
return Err(anyhow!("signature failed"));
};
let signature = res.blob();
match signature {
None => Err(anyhow!("no blob")),
Some(b) => {
let sign_response = sign::SignResponse {
signature: b.bytes().to_vec(),
};
let sign_response_bytes = serde_json::to_vec(&sign_response)?;
Response::new()
.blob(blob)
.body(sign_response_bytes)
.send()?;
Ok(())
}
}
}
// NOTE net:distro:sys prepends the node ID to every message before signing
fn handle_verify(our: &Address, req: sign::VerifyRequest) -> Result<()> {
kiprintln!("handling verifyy");
let Some(blob) = get_blob() else {
return Err(anyhow!("no blob"));
};
let process = our.to_owned().process;
let from = Address::new(req.node, process);
kiprintln!("handling verify");
let body = rmp_serde::to_vec(&NetAction::Verify {
from,
signature: req.signature,
})?;
let res = Request::to(("our", "net", "distro", "sys"))
.blob(blob)
.body(body)
.send_and_await_response(10)??;
let resp = rmp_serde::from_slice::<NetResponse>(res.body())?;
match resp {
NetResponse::Verified(is_good) => {
Response::new().body(serde_json::to_vec(&is_good)?).send()?;
Ok(())
}
_ => Err(anyhow!("weird response")),
}
}