mirror of
https://github.com/aljazceru/pubky-core.git
synced 2025-12-31 12:54:35 +01:00
feat(pubky): add wasm mod
This commit is contained in:
5
Cargo.lock
generated
5
Cargo.lock
generated
@@ -1252,6 +1252,8 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"flume",
|
||||
"futures",
|
||||
"js-sys",
|
||||
"pkarr",
|
||||
"pubky-common",
|
||||
"pubky_homeserver",
|
||||
@@ -1259,6 +1261,9 @@ dependencies = [
|
||||
"tokio",
|
||||
"ureq",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
3
js/pubky/README.md
Normal file
3
js/pubky/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Pubky
|
||||
|
||||
This is a JavaScript implementation of a Pubky protocol client-side tools.
|
||||
9
js/pubky/examples/basic.js
Normal file
9
js/pubky/examples/basic.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import { PubkyClient } from '../src/index.js'
|
||||
|
||||
main()
|
||||
|
||||
async function main() {
|
||||
let client = new PubkyClient()
|
||||
|
||||
console.log(client)
|
||||
}
|
||||
5
js/pubky/src/index.js
Normal file
5
js/pubky/src/index.js
Normal file
@@ -0,0 +1,5 @@
|
||||
// import { PubkyClient as _PubkyClient } from './lib/client.js'
|
||||
// import { PubkyError as _PubkyError } from './lib/error.js'
|
||||
//
|
||||
// export const PubkyClient = _PubkyClient;
|
||||
// export const PubkyError = _PubkyError;
|
||||
102
js/pubky/src/lib/client.js
Normal file
102
js/pubky/src/lib/client.js
Normal file
@@ -0,0 +1,102 @@
|
||||
import Pkarr, { SignedPacket } from 'pkarr'
|
||||
import { URL } from 'url'
|
||||
|
||||
// import { AuthnSignature, crypto } from '@pubky/common'
|
||||
|
||||
import * as crypto from '../common/crypto.js'
|
||||
|
||||
// import { Pubky } from './pubky.js'
|
||||
import fetch from './fetch.js'
|
||||
|
||||
|
||||
const DEFAULT_PKARR_RELAY = new URL('https://relay.pkarr.org')
|
||||
|
||||
export class PubkyClient {
|
||||
// TODO: use DHT in nodejs
|
||||
#pkarrRelay
|
||||
|
||||
crypto = crypto
|
||||
static crypto = crypto
|
||||
|
||||
/**
|
||||
* @param {object} [options={}]
|
||||
* @param {URL} [options.pkarrRelay]
|
||||
*
|
||||
* @param {{relay: string, bootstrap: Array<{host: string, port: number}>}} [options.testnet]
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
this.#pkarrRelay = options.pkarrRelay || DEFAULT_PKARR_RELAY
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish the SVCB record for `_pubky.<public_key>`.
|
||||
* @param {crypto.KeyPair} keypair
|
||||
* @param {String} host
|
||||
*/
|
||||
async publishPubkyHomeserver(keypair, host) {
|
||||
|
||||
let existing = await (async () => {
|
||||
try {
|
||||
return (await Pkarr.relayGet(this.#pkarrRelay.toString(), keypair.publicKey().bytes)).packet()
|
||||
} catch (error) {
|
||||
return {
|
||||
id: 0,
|
||||
type: 'response',
|
||||
flags: 0,
|
||||
answers: []
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
let answers = [
|
||||
];
|
||||
|
||||
for (let answer of existing.answers) {
|
||||
if (!answer.name.startsWith("_pubky")) {
|
||||
answers.push(answer)
|
||||
}
|
||||
}
|
||||
|
||||
let signedPacket = SignedPacket.fromPacket(keypair, {
|
||||
id: 0,
|
||||
type: 'response',
|
||||
flags: 0,
|
||||
answers: [
|
||||
...answers,
|
||||
{
|
||||
name: '_pubky.', type: 'SVCB', ttl: 7200, data:
|
||||
|
||||
Buffer.from(
|
||||
|
||||
)
|
||||
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// let mut packet = Packet:: new_reply(0);
|
||||
//
|
||||
// if let Some(existing) = self.pkarr.resolve(& keypair.public_key()) ? {
|
||||
// for answer in existing.packet().answers.iter().cloned() {
|
||||
// if !answer.name.to_string().starts_with("_pubky") {
|
||||
// packet.answers.push(answer.into_owned())
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// let svcb = SVCB::new (0, host.try_into() ?);
|
||||
//
|
||||
// packet.answers.push(pkarr:: dns:: ResourceRecord:: new (
|
||||
// "_pubky".try_into().unwrap(),
|
||||
// pkarr:: dns:: CLASS:: IN,
|
||||
// 60 * 60,
|
||||
// pkarr:: dns:: rdata:: RData:: SVCB(svcb),
|
||||
// ));
|
||||
//
|
||||
// let signed_packet = SignedPacket:: from_packet(keypair, & packet) ?;
|
||||
//
|
||||
// self.pkarr.publish(& signed_packet) ?;
|
||||
}
|
||||
}
|
||||
|
||||
export default PubkyClient
|
||||
1
js/pubky/src/lib/error.js
Normal file
1
js/pubky/src/lib/error.js
Normal file
@@ -0,0 +1 @@
|
||||
export class PubkyError extends Error { }
|
||||
11
js/pubky/src/lib/fetch-browser.js
Normal file
11
js/pubky/src/lib/fetch-browser.js
Normal file
@@ -0,0 +1,11 @@
|
||||
/* eslint-disable no-prototype-builtins */
|
||||
const g =
|
||||
(typeof globalThis !== 'undefined' && globalThis) ||
|
||||
// eslint-disable-next-line no-undef
|
||||
(typeof self !== 'undefined' && self) ||
|
||||
// eslint-disable-next-line no-undef
|
||||
(typeof global !== 'undefined' && global) ||
|
||||
{}
|
||||
|
||||
// @ts-ignore
|
||||
export default g.fetch
|
||||
3
js/pubky/src/lib/fetch.js
Normal file
3
js/pubky/src/lib/fetch.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import fetch from 'node-fetch-cache'
|
||||
|
||||
export default fetch
|
||||
@@ -3,16 +3,35 @@ name = "pubky"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
pkarr = "2.1.0"
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
pubky-common = { version = "0.1.0", path = "../pubky-common" }
|
||||
|
||||
pkarr = "2.1.0"
|
||||
ureq = { version = "2.10.0", features = ["cookies"] }
|
||||
thiserror = "1.0.62"
|
||||
url = "2.5.2"
|
||||
flume = { version = "0.11.0", features = ["select", "eventual-fairness"], default-features = false }
|
||||
bytes = "1.6.1"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
futures = "0.3.29"
|
||||
js-sys = "0.3.69"
|
||||
wasm-bindgen = "0.2.92"
|
||||
wasm-bindgen-futures = "0.4.42"
|
||||
web-sys = { version = "0.3.69", features = [
|
||||
"console",
|
||||
"Request",
|
||||
"RequestInit",
|
||||
"RequestMode",
|
||||
"Response",
|
||||
"Window",
|
||||
] }
|
||||
|
||||
[dev-dependencies]
|
||||
pubky_homeserver = { path = "../pubky-homeserver" }
|
||||
tokio = "1.37.0"
|
||||
|
||||
@@ -1,8 +1,30 @@
|
||||
#![allow(unused)]
|
||||
|
||||
mod client;
|
||||
mod client_async;
|
||||
mod error;
|
||||
macro_rules! if_not_wasm {
|
||||
($($item:item)*) => {$(
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
$item
|
||||
)*}
|
||||
}
|
||||
|
||||
pub use client::PubkyClient;
|
||||
pub use error::Error;
|
||||
macro_rules! if_wasm {
|
||||
($($item:item)*) => {$(
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
$item
|
||||
)*}
|
||||
}
|
||||
|
||||
if_not_wasm! {
|
||||
mod client;
|
||||
mod client_async;
|
||||
mod error;
|
||||
|
||||
pub use client::PubkyClient;
|
||||
pub use error::Error;
|
||||
}
|
||||
|
||||
if_wasm! {
|
||||
mod wasm;
|
||||
|
||||
pub use wasm::{PubkyClient, Keypair};
|
||||
}
|
||||
|
||||
6
pubky/src/wasm.rs
Normal file
6
pubky/src/wasm.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
mod keys;
|
||||
|
||||
mod client;
|
||||
|
||||
pub use client::PubkyClient;
|
||||
pub use keys::Keypair;
|
||||
73
pubky/src/wasm/client.rs
Normal file
73
pubky/src/wasm/client.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen_futures::JsFuture;
|
||||
use web_sys::RequestMode;
|
||||
|
||||
use pkarr::PkarrRelayClient;
|
||||
|
||||
use super::Keypair;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct Error {}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct PubkyClient {
|
||||
pkarr: PkarrRelayClient,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl PubkyClient {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
pkarr: PkarrRelayClient::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Signup to a homeserver and update Pkarr accordingly.
|
||||
///
|
||||
/// The homeserver is a Pkarr domain name, where the TLD is a Pkarr public key
|
||||
/// for example "pubky.o4dksfbqk85ogzdb5osziw6befigbuxmuxkuxq8434q89uj56uyy"
|
||||
#[wasm_bindgen]
|
||||
pub fn signup(&self, secret_key: Keypair, homeserver: &str) -> Result<(), JsValue> {
|
||||
// let (audience, mut url) = self.resolve_endpoint(homeserver)?;
|
||||
|
||||
// url.set_path(&format!("/{}", keypair.public_key()));
|
||||
|
||||
// let body = AuthnSignature::generate(keypair, &audience).as_bytes();
|
||||
|
||||
// fetch_base(url.to_string(), "PUT", body).await?;
|
||||
|
||||
// self.publish_pubky_homeserver(keypair, homeserver);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
async fn fetch_base(
|
||||
url: &String,
|
||||
method: &str,
|
||||
body: Option<Vec<u8>>,
|
||||
) -> Result<web_sys::Response, JsValue> {
|
||||
let mut opts = web_sys::RequestInit::new();
|
||||
opts.method(method);
|
||||
opts.mode(RequestMode::Cors);
|
||||
|
||||
if let Some(body) = body {
|
||||
let body_bytes: &[u8] = &body;
|
||||
let body_array: js_sys::Uint8Array = body_bytes.into();
|
||||
let js_value: &JsValue = body_array.as_ref();
|
||||
opts.body(Some(js_value));
|
||||
}
|
||||
|
||||
let js_request = web_sys::Request::new_with_str_and_init(url, &opts)?;
|
||||
// .map_err(|error| Error::JsError(error))?;
|
||||
|
||||
let window = web_sys::window().unwrap();
|
||||
let response = JsFuture::from(window.fetch_with_request(&js_request)).await?;
|
||||
// .map_err(|error| Error::JsError(error))?;
|
||||
|
||||
let response: web_sys::Response = response.dyn_into()?;
|
||||
// .map_err(|error| Error::JsError(error))?
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
15
pubky/src/wasm/keys.rs
Normal file
15
pubky/src/wasm/keys.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct Keypair(pkarr::Keypair);
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Keypair {
|
||||
#[wasm_bindgen]
|
||||
pub fn from_secret_key(secret_key: js_sys::Uint8Array) -> Self {
|
||||
let mut bytes = [0; 32];
|
||||
secret_key.copy_to(&mut bytes);
|
||||
|
||||
Self(pkarr::Keypair::from_secret_key(&bytes))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user