@decentnetwork/beagle 0.1.60 → 0.1.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/desktop/app.js +6 -3
- package/dist/server.js +62 -10
- package/package.json +2 -2
package/dist/desktop/app.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
window.__DK_UI_VERSION="0.1.
|
|
1
|
+
window.__DK_UI_VERSION="0.1.61";
|
|
2
2
|
"use strict";
|
|
3
3
|
(() => {
|
|
4
4
|
// packages/beagle-ui/dist/beagle-ui.js
|
|
@@ -2925,11 +2925,14 @@ ${peer.address}`
|
|
|
2925
2925
|
return /* @__PURE__ */ React.createElement(Card, { label: zh ? "\u663E\u793A" : "Display" }, /* @__PURE__ */ React.createElement("div", { style: { ...row, borderBottom: "1px solid var(--line)" } }, /* @__PURE__ */ React.createElement("span", { style: name }, zh ? "\u8BED\u8A00" : "Language"), seg("lang", t.lang, (v) => setTweak("lang", v), [["en", "EN"], ["zh", "\u4E2D\u6587"]])), /* @__PURE__ */ React.createElement("div", { style: row }, /* @__PURE__ */ React.createElement("span", { style: name }, zh ? "\u4E3B\u9898" : "Theme"), seg("theme", t.theme, (v) => setTweak("theme", v), [["dark", zh ? "\u6DF1\u8272" : "Dark"], ["light", zh ? "\u6D45\u8272" : "Light"]])));
|
|
2926
2926
|
}
|
|
2927
2927
|
function ProfileTab({ T, me, onEdit, t, setTweak }) {
|
|
2928
|
+
var _a;
|
|
2928
2929
|
const [qr, setQr] = React.useState(null);
|
|
2929
2930
|
const [editing, setEditing] = React.useState(false);
|
|
2930
2931
|
const [ensRec, setEnsRec] = React.useState(null);
|
|
2931
|
-
const
|
|
2932
|
-
const
|
|
2932
|
+
const pubPunk = ensRec && ensRec.nft === "CryptoPunks" && ensRec.nftid > 0 ? ensRec.nftid : null;
|
|
2933
|
+
const pubAvatar = ensRec && ensRec.texts && ensRec.texts.avatar || null;
|
|
2934
|
+
const punkId = (_a = me.punkId) != null ? _a : pubPunk;
|
|
2935
|
+
const upAvatar = me.avatarUrl || pubAvatar;
|
|
2933
2936
|
return /* @__PURE__ */ React.createElement("div", { style: { flex: 1, overflow: "auto", background: "var(--bg)" } }, /* @__PURE__ */ React.createElement("div", { style: { maxWidth: 760, margin: "0 auto", padding: "24px 28px 60px", display: "flex", flexDirection: "column", gap: 24 } }, /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 18, padding: "20px 22px", borderRadius: 14, background: "var(--panel)", border: "1px solid var(--line)" } }, /* @__PURE__ */ React.createElement("div", { style: { position: "relative" } }, upAvatar ? /* @__PURE__ */ React.createElement("img", { src: upAvatar, alt: "", width: 68, height: 68, style: { width: 68, height: 68, borderRadius: 16, objectFit: "cover", background: "var(--panel-2)" } }) : punkId != null ? /* @__PURE__ */ React.createElement(DkPunkAvatar, { id: punkId, size: 68, radius: 16, fallbackSeed: me.userId }) : /* @__PURE__ */ React.createElement(DkIdenticon, { seed: me.userId, size: 68, radius: 16 }), /* @__PURE__ */ React.createElement("span", { style: { position: "absolute", right: -3, bottom: -3, width: 18, height: 18, borderRadius: 999, background: "var(--online)", border: "3px solid var(--panel)" } })), /* @__PURE__ */ React.createElement("div", { style: { flex: 1, minWidth: 0 } }, /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 10 } }, /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 22, fontWeight: 700, letterSpacing: -0.5, color: "var(--text)" } }, me.name), /* @__PURE__ */ React.createElement(Tag, { tone: "ok" }, "online"), me.isExit && /* @__PURE__ */ React.createElement(Tag, { tone: "warn" }, "exit", me.exitRegion ? ` \xB7 ${me.exitRegion.toUpperCase()}` : "")), /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--mono)", fontSize: 13, color: "var(--dim)", marginTop: 4 } }, me.handle), me.description ? /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--faint)", marginTop: 3 } }, me.description) : null), /* @__PURE__ */ React.createElement(Btn, { icon: "edit", onClick: () => setEditing(true) }, T.editProfile)), /* @__PURE__ */ React.createElement(Card, { label: T.identity }, /* @__PURE__ */ React.createElement(FieldRow, { T, label: T.userId, value: me.userId, copy: true, qr: true, onQr: (v, l) => setQr({ value: v, label: l }) }), /* @__PURE__ */ React.createElement(FieldRow, { T, label: T.carrierAddr, value: me.carrier, copy: true, qr: true, onQr: (v, l) => setQr({ value: v, label: l }) }), /* @__PURE__ */ React.createElement(FieldRow, { T, label: T.netKey, value: me.netKey, copy: true, last: true })), /* @__PURE__ */ React.createElement(DkEnsCard, { T, me, onRecord: setEnsRec }), typeof me.autoAccept === "boolean" && /* @__PURE__ */ React.createElement(Card, { label: T && T.friendsSettings || "Friends" }, /* @__PURE__ */ React.createElement("label", { style: { display: "flex", alignItems: "center", gap: 13, padding: "14px 16px", cursor: "pointer" } }, /* @__PURE__ */ React.createElement(
|
|
2934
2937
|
"input",
|
|
2935
2938
|
{
|
package/dist/server.js
CHANGED
|
@@ -550,10 +550,15 @@ const CONNECT_PAGE = `<!doctype html>
|
|
|
550
550
|
<body>
|
|
551
551
|
<div class="card">
|
|
552
552
|
<div class="brand"><span class="d"></span>Beagle</div>
|
|
553
|
-
<h1>Sign in</h1>
|
|
554
|
-
<p class="sub"><span id="origin" class="origin">…</span> wants to sign you in with your Beagle identity.</p>
|
|
553
|
+
<h1 id="headline">Sign in</h1>
|
|
554
|
+
<p class="sub"><span id="origin" class="origin">…</span><span id="leadTail"> wants to sign you in with your Beagle identity.</span></p>
|
|
555
|
+
<div id="targetRow" class="id" hidden>
|
|
556
|
+
<div class="lbl">Friend request to</div>
|
|
557
|
+
<div id="targetName" class="who" hidden></div>
|
|
558
|
+
<div id="targetAddr" class="userid"></div>
|
|
559
|
+
</div>
|
|
555
560
|
<div class="id">
|
|
556
|
-
<div class="lbl">Your identity</div>
|
|
561
|
+
<div id="idLabel" class="lbl">Your identity</div>
|
|
557
562
|
<div id="who" class="who" hidden></div>
|
|
558
563
|
<div id="userid" class="userid">loading…</div>
|
|
559
564
|
</div>
|
|
@@ -562,21 +567,49 @@ const CONNECT_PAGE = `<!doctype html>
|
|
|
562
567
|
<button id="deny" class="btn ghost">Deny</button>
|
|
563
568
|
<button id="approve" class="btn solid" disabled>Approve</button>
|
|
564
569
|
</div>
|
|
565
|
-
<p class="note">Approving sends the site a signature bound to that site, proving you control this identity. Your private key never leaves this device.</p>
|
|
570
|
+
<p id="note" class="note">Approving sends the site a signature bound to that site, proving you control this identity. Your private key never leaves this device.</p>
|
|
566
571
|
</div>
|
|
567
572
|
<script>
|
|
568
573
|
(function(){
|
|
569
574
|
var qs=new URLSearchParams(location.search);
|
|
570
575
|
var origin=qs.get("origin")||"", nonce=qs.get("nonce")||"";
|
|
576
|
+
// "signin" (default) or "add". One hands the site a signature; the other
|
|
577
|
+
// asks a stranger to be your friend. Both need consent, and only the second
|
|
578
|
+
// changes anything — so they are separate actions, never one grant.
|
|
579
|
+
var action=qs.get("action")==="add"?"add":"signin";
|
|
580
|
+
var target=(qs.get("address")||"").trim(), targetName=(qs.get("name")||"").trim();
|
|
571
581
|
var oEl=document.getElementById("origin"), errEl=document.getElementById("err");
|
|
572
582
|
var approve=document.getElementById("approve"), deny=document.getElementById("deny");
|
|
573
583
|
oEl.textContent=origin||"(unknown site)";
|
|
574
584
|
function fail(m){errEl.textContent=m;errEl.hidden=false;}
|
|
575
|
-
function reply(data){
|
|
585
|
+
function reply(data){
|
|
586
|
+
if(!window.opener||!validOrigin) return;
|
|
587
|
+
// A friend request is NOT an auth assertion and must never be mistaken for
|
|
588
|
+
// one by a listener written before this existed — hence its own type.
|
|
589
|
+
var base=action==="add"?{type:"beagle-action",nonce:nonce,action:"add"}:{type:"decent-auth",nonce:nonce};
|
|
590
|
+
window.opener.postMessage(Object.assign(base,data),origin);
|
|
591
|
+
}
|
|
576
592
|
var validOrigin=false;
|
|
577
593
|
try{var u=new URL(origin); validOrigin=(u.protocol==="http:"||u.protocol==="https:")&&u.origin===origin;}catch(e){}
|
|
578
594
|
if(!validOrigin) fail("This sign-in request has an invalid origin and was blocked.");
|
|
579
|
-
if(nonce.length===0||nonce.length>512){ validOrigin=false; fail("This
|
|
595
|
+
if(nonce.length===0||nonce.length>512){ validOrigin=false; fail("This request is missing a valid nonce."); }
|
|
596
|
+
if(action==="add"&&!(target.length>=50&&target.length<=60&&/^[1-9A-HJ-NP-Za-km-z]+$/.test(target))){
|
|
597
|
+
validOrigin=false; fail("That does not look like a Beagle address, so nothing was sent.");
|
|
598
|
+
}
|
|
599
|
+
if(action==="add"){
|
|
600
|
+
document.title="Add a friend on Beagle";
|
|
601
|
+
document.getElementById("headline").textContent="Add a friend";
|
|
602
|
+
// Set the TAIL, not the whole paragraph: rewriting it would remove the
|
|
603
|
+
// #origin span, and the site name would then render as "null".
|
|
604
|
+
document.getElementById("leadTail").textContent=" wants to send a friend request from your Beagle identity.";
|
|
605
|
+
document.getElementById("targetRow").hidden=false;
|
|
606
|
+
var tn=document.getElementById("targetName");
|
|
607
|
+
tn.textContent=targetName||""; tn.hidden=!targetName;
|
|
608
|
+
document.getElementById("targetAddr").textContent=target;
|
|
609
|
+
document.getElementById("idLabel").textContent="Sent as";
|
|
610
|
+
approve.textContent="Send request";
|
|
611
|
+
document.getElementById("note").textContent="The other person sees your name and has to accept. Nothing is shared with the site — it only asked; your Beagle sent it.";
|
|
612
|
+
}
|
|
580
613
|
fetch("/api/state").then(function(r){return r.json();}).then(function(s){
|
|
581
614
|
var uid=(s.me&&s.me.userid)||"", nm=(s.me&&s.me.name)||"";
|
|
582
615
|
document.getElementById("userid").textContent=uid||"(no identity)";
|
|
@@ -586,12 +619,24 @@ const CONNECT_PAGE = `<!doctype html>
|
|
|
586
619
|
}).catch(function(){ fail("Could not reach the local agentnet daemon."); });
|
|
587
620
|
deny.onclick=function(){ reply({error:"denied"}); setTimeout(function(){window.close();},60); };
|
|
588
621
|
approve.onclick=function(){
|
|
589
|
-
approve.disabled=true;
|
|
622
|
+
approve.disabled=true;
|
|
623
|
+
if(action==="add"){
|
|
624
|
+
approve.textContent="Sending…";
|
|
625
|
+
fetch("/api/add",{method:"POST",headers:{"content-type":"application/json"},
|
|
626
|
+
body:JSON.stringify({address:target,hello:targetName?("Hi — we met on "+new URL(origin).host+"."):""})})
|
|
627
|
+
.then(function(r){return r.json();})
|
|
628
|
+
.then(function(j){ if(j.ok===false) throw new Error(j.error||"could not send");
|
|
629
|
+
reply({ok:true,address:target}); setTimeout(function(){window.close();},60); })
|
|
630
|
+
.catch(function(e){ approve.disabled=false; approve.textContent="Send request";
|
|
631
|
+
fail("Could not send the request: "+e.message); });
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
approve.textContent="Signing…";
|
|
590
635
|
fetch("/api/connect-approve",{method:"POST",headers:{"content-type":"application/json"},
|
|
591
636
|
body:JSON.stringify({origin:origin,nonce:nonce})})
|
|
592
637
|
.then(function(r){return r.json();})
|
|
593
638
|
.then(function(j){ if(!j.ok) throw new Error(j.error||"sign failed");
|
|
594
|
-
reply({userid:j.userid,sig:j.sig,name:j.name,avatar:j.avatar}); setTimeout(function(){window.close();},60); })
|
|
639
|
+
reply({userid:j.userid,sig:j.sig,name:j.name,avatar:j.avatar,punkId:j.punkId}); setTimeout(function(){window.close();},60); })
|
|
595
640
|
.catch(function(e){ approve.disabled=false; approve.textContent="Approve"; fail("Signing failed: "+e.message); });
|
|
596
641
|
};
|
|
597
642
|
})();
|
|
@@ -734,14 +779,17 @@ export function startBeagleServer(opts) {
|
|
|
734
779
|
// neither is part of what the signature proves.
|
|
735
780
|
let name = "";
|
|
736
781
|
let avatar = null;
|
|
782
|
+
let punkId = null;
|
|
783
|
+
const diagId = await opts.call({ op: "diag" });
|
|
737
784
|
try {
|
|
738
|
-
const diag =
|
|
785
|
+
const diag = diagId;
|
|
739
786
|
name = ((diag.ok ? diag.data : {})?.node?.name) ?? "";
|
|
740
787
|
const pub = (await ensPublicByUserid(1200)).get(userid);
|
|
741
788
|
if (pub) {
|
|
742
789
|
if (!name)
|
|
743
790
|
name = pub.displayName ?? "";
|
|
744
791
|
avatar = pub.avatarUrl ?? null;
|
|
792
|
+
punkId = pub.punkId;
|
|
745
793
|
if (!avatar && pub.punkId != null) {
|
|
746
794
|
const punk = await punksFetch(`/api/punks/${pub.punkId}`).catch(() => null);
|
|
747
795
|
avatar = punk?.image ?? null;
|
|
@@ -749,7 +797,11 @@ export function startBeagleServer(opts) {
|
|
|
749
797
|
}
|
|
750
798
|
}
|
|
751
799
|
catch { /* identity is what matters; the trimmings are best-effort */ }
|
|
752
|
-
|
|
800
|
+
// The address, not just the userid: a friend request needs the full
|
|
801
|
+
// address (key + nospam + checksum), so without it a site that signed
|
|
802
|
+
// someone in still cannot offer to introduce them to anyone.
|
|
803
|
+
const address = ((diagId.ok ? diagId.data : {})?.identity?.address) ?? "";
|
|
804
|
+
sendJson(res, 200, { ok: true, userid, address, sig: r.data?.sig ?? "", name, avatar, punkId });
|
|
753
805
|
return;
|
|
754
806
|
}
|
|
755
807
|
// ── beagles.eth name registration ──
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decentnetwork/beagle",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.61",
|
|
4
4
|
"description": "Beagle — P2P chat, file transfer and calls for regular users, on the Decent Network. No admin privilege required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"yargs": "^17.7.2"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@decentnetwork/beagle-ui": "0.1.
|
|
36
|
+
"@decentnetwork/beagle-ui": "0.1.2",
|
|
37
37
|
"@types/js-yaml": "^4.0.9",
|
|
38
38
|
"@types/node": "^20.11.0",
|
|
39
39
|
"@types/yargs": "^17.0.32",
|