@pipeup/inbox 0.8.2 → 0.9.1
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/inbox.esm.js +2 -2
- package/dist/inbox.min.js +2 -2
- package/dist/pipeup+inbox.min.js +3 -3
- package/package.json +2 -2
package/dist/inbox.esm.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
2
|
-
${
|
|
1
|
+
var V="0123456789ABCDEFGHJKMNPQRSTVWXYZ",b=new TextEncoder,Y=n=>{let e="";for(let t of n)e+=String.fromCharCode(t);return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")},h=n=>{let e=atob(n.replace(/-/g,"+").replace(/_/g,"/")),t=new Uint8Array(e.length);for(let r=0;r<e.length;r++)t[r]=e.charCodeAt(r);return t},$=async n=>new Uint8Array(await crypto.subtle.digest("SHA-256",n)),v=(...n)=>{let e=new Uint8Array(n.reduce((r,o)=>r+o.length,0)),t=0;for(let r of n)e.set(r,t),t+=r.length;return e};async function B(n){let e=await $(v(b.encode("pipeup-inbox/1"),h(n))),t=0,r=0,o="";for(let a of e)for(r=r<<8|a,t+=8;t>=5&&o.length<26;)o+=V[r>>>t-5&31],t-=5;return o}var Q=n=>{let e=0;for(let t of n)if(t===0)e+=8;else return e+Math.clz32(t)-24;return e};async function C(n,e,t){for(let r=0;;r++)if(Q(await $(b.encode(`${n}|${e}|${r}`)))>=t)return String(r)}var tt=Uint8Array.from([48,46,2,1,0,48,5,6,3,43,101,110,4,34,4,32]);async function M(n,e,t){let r=await crypto.subtle.importKey("raw",n,"HKDF",!1,["deriveBits"]);return new Uint8Array(await crypto.subtle.deriveBits({name:"HKDF",hash:"SHA-256",salt:new Uint8Array,info:b.encode(e)},r,t*8))}async function I(n){let e=await M(h(n),"pipeup-inbox/x25519",32),t=await crypto.subtle.importKey("pkcs8",v(tt,e),{name:"X25519"},!0,["deriveBits"]),r=await crypto.subtle.exportKey("jwk",t);return{privateKey:t,publicKey:r.x}}var D=async(n,e)=>crypto.subtle.importKey("raw",await M(v(n,e),"pipeup-inbox/seal",32),"AES-GCM",!1,["encrypt","decrypt"]);async function L(n,e){let t=await crypto.subtle.generateKey({name:"X25519"},!0,["deriveBits"]),r=new Uint8Array(await crypto.subtle.exportKey("raw",t.publicKey)),o=await crypto.subtle.importKey("raw",h(n),{name:"X25519"},!1,[]),a=new Uint8Array(await crypto.subtle.deriveBits({name:"X25519",public:o},t.privateKey,256)),c=crypto.getRandomValues(new Uint8Array(12)),m=new Uint8Array(await crypto.subtle.encrypt({name:"AES-GCM",iv:c},await D(a,r),b.encode(e)));return`pi1.${Y(v(r,c,m))}`}async function _(n,e){try{let t=h(e.replace(/^pi1\./,"")),r=t.slice(0,32),o=t.slice(32,44),a=await crypto.subtle.importKey("raw",r,{name:"X25519"},!1,[]),c=new Uint8Array(await crypto.subtle.deriveBits({name:"X25519",public:a},n.privateKey,256)),m=await crypto.subtle.decrypt({name:"AES-GCM",iv:o},await D(c,r),t.slice(44));return new TextDecoder().decode(m)}catch{return null}}async function N(n,e,t,r){try{let o=await crypto.subtle.importKey("raw",h(n),{name:"Ed25519"},!1,["verify"]);return await crypto.subtle.verify({name:"Ed25519"},o,h(r),b.encode(`pipeup:${e}
|
|
2
|
+
${t}`))}catch{return!1}}var S=class{constructor(e,t){this.base=e;this.signal=t}url(e,t=""){return`${this.base.replace(/\/+$/,"")}/i/${e}${t}`}async call(e,t,r,o={}){return fetch(t,{method:e,credentials:"omit",referrerPolicy:"no-referrer",mode:"cors",signal:this.signal,headers:{...r===void 0?{}:{"content-type":"text/plain;charset=UTF-8"},...o},body:r===void 0?void 0:JSON.stringify(r)})}async putKey(e,t,r,o){return(await this.call("PUT",this.url(e,"/key"),{ed:t,pub:r,sig:o})).ok}async getKey(e){let t=await this.call("GET",this.url(e,"/key"));return t.ok?(await t.json()).pub:null}async leave(e,t){let r=14;for(let o=0;o<2;o++){let a=await this.call("POST",this.url(e),{ct:t,work:await C(e,t,r)});if(a.ok)return!0;let c=a.status===403?(await a.json().catch(()=>({}))).bits:void 0;if(!c||c<=r||c>24)return!1;r=c}return!1}async list(e,t){let r=await this.call("GET",`${this.url(e)}${t?`?since=${t}`:""}`);if(r.status===404)return{notes:[],next:t};if(!r.ok)throw new Error("the inbox service didn't answer");return await r.json()}async remove(e,t,r,o){return(await this.call("DELETE",this.url(e,`/${t}`),void 0,{"x-pipeup-key":r,"x-pipeup-sig":o})).ok}};var w=(n,e)=>e?e.getAttribute(n):globalThis.Pipeup?.setting?.(n)??globalThis.document?.documentElement.getAttribute(n)??null;var Ot=2n**256n-2n**32n-977n;var R="pipeup:inbox-on",j=["M12 12a4 4 0 1 0 0-8a4 4 0 0 0 0 8z","M4 20c0-4 3.6-6 8-6s8 2 8 6"],z=/^[A-Za-z0-9_-]{43}$/,st=()=>{try{return localStorage.getItem(R)==="1"}catch{return!1}},at=n=>{try{localStorage.setItem(R,n?"1":"0")}catch{}};function ct(n){let e=w("data-pipeup-inbox",n)??"";try{let t=new URL(e),r=t.hostname==="localhost"||t.hostname==="127.0.0.1"||t.hostname==="[::1]";return t.protocol==="https:"||t.protocol==="http:"&&r?e:""}catch{return""}}var H=n=>JSON.stringify([n.v,n.from,n.name,n.text,n.link,n.title,n.at]),pt=n=>{try{let e=new URL(n);return e.protocol==="https:"||e.protocol==="http:"||e.protocol==="file:"?e.href:null}catch{return null}};function dt(){return{id:"inbox",api:1,version:"0.7.0-beta.1",needs:["menu","notify","panel","sign"],network:{when:"after-consent",to:["the inbox service the page names (data-pipeup-inbox)"],says:"Only after you switch on Mentions by inbox: when you mention someone, a short note (who, your words, the page's address) is left for them at the page's inbox service, sealed so only they can read it; and your own inbox is checked there. The service sees that a note arrived, its size and when, and your network address, never who it is from or what it says."},setup(n){let e=ct();if(!e)return n.off('the page names no inbox service (data-pipeup-inbox="https://\u2026")');let t=new S(e,n.signal),r=n.document.me,o=Math.max(1,Number(w("data-pipeup-inbox-poll"))||60),a=st(),c=null,m="",P=0,f=new Map,x=null,A=null,F=async()=>{if(c)return c;let s=await I(await n.sign("seed","x25519")),d=await B(r);return await t.putKey(d,r,s.publicKey,await n.sign("key",`${d}:${s.publicKey}`)),c={key:s,id:d}},U=()=>{x?.remove(),x=null,f.size&&(x=n.addMenuItem({id:"waiting",icon:j,label:()=>"Mentions waiting",hint:()=>"People who mentioned you, on pages you may not have opened",count:()=>String(f.size),select:G}))},G=()=>{let s=document.createElement("div"),d=()=>{s.replaceChildren(),f.size||s.append(Object.assign(document.createElement("p"),{textContent:"Nothing waiting."}));for(let p of f.values()){let i=document.createElement("div");i.append(Object.assign(document.createElement("strong"),{textContent:`${p.name||"Someone"} mentioned you`}),Object.assign(document.createElement("p"),{textContent:p.text}),Object.assign(document.createElement("small"),{textContent:`${p.title} \xB7 ${p.link}`}));let y=pt(p.link),l=document.createElement("div");if(y){let g=Object.assign(document.createElement("button"),{type:"button",textContent:"Open the page"});g.addEventListener("click",()=>window.open(y,"_blank","noopener,noreferrer")),l.append(g)}let u=Object.assign(document.createElement("button"),{type:"button",textContent:"Dismiss"});u.addEventListener("click",()=>void X(p.id).then(d)),l.append(u),i.append(l),s.append(i)}};d(),A=n.openPanel(s,{label:"Mentions waiting",onClose:()=>A=null})},X=async s=>{c&&(await t.remove(c.id,s,r,await n.sign("delete",`${c.id}:${s}`))&&f.delete(s),U())},O=async()=>{try{let s=await F(),d=await t.list(s.id,m);m=d.next;let p=0;for(let{id:i,ct:y}of d.notes){let l=await _(s.key,y);if(!(!l||f.has(i)))try{let[u,g]=JSON.parse(l);if(u.v!==1||!z.test(u.from)||!await N(u.from,"inbox/note",H(u),g))continue;f.set(i,{...u,id:i}),p++}catch{}}p&&(U(),n.notify(`${p} new mention${p===1?"":"s"} waiting`))}catch{}},J=async s=>{let d=s.text??"",p=[...new Set((s.mentions??[]).map(i=>i.ref).filter(i=>z.test(i)&&i!==r))];for(let i of p)try{let y=await B(i),l=await t.getKey(y);if(!l)continue;let u={v:1,from:r,name:n.document.name,text:d,link:location.href,title:document.title,at:Date.now()},g=await n.sign("note",H(u));await t.leave(y,await L(l,JSON.stringify([u,g])))}catch{}},K=()=>{O(),P=window.setInterval(()=>!document.hidden&&void O(),o*1e3)},Z=()=>{window.clearInterval(P),f.clear(),U(),A?.close()},W=n.addMenuItem({id:"inbox",icon:j,label:()=>"Mentions by inbox",hint:()=>`Leaves a sealed note for people you mention, at ${new URL(e).host}, and checks your own inbox there. The service sees that a note arrived, its size and when, and your network address, never who it is from or what it says.`,checked:()=>a,select:()=>{a=!a,at(a),a?K():Z()}}),q=n.document.onChange((s,d,p)=>{if(!(!a||p!=="local"))for(let{body:i}of d)i.author===r&&i.mentions?.length&&(i.kind==="create"||i.kind==="reply")&&J(i)});return a&&K(),()=>{q(),window.clearInterval(P),W.remove(),x?.remove(),A?.close()}}}}export{dt as default};
|
package/dist/inbox.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";(()=>{function
|
|
2
|
-
${
|
|
1
|
+
"use strict";(()=>{function B(e){let t=globalThis;(t.pipeupAddons||=[]).push(e),typeof addEventListener=="function"&&addEventListener("load",()=>{t.Pipeup||console.error(`pipeup: the "${e.id}" add-on needs Pipeup on the page too; load pipeup.min.js.`)},{once:!0})}var b=(e,t)=>t?t.getAttribute(e):globalThis.Pipeup?.setting?.(e)??globalThis.document?.documentElement.getAttribute(e)??null;var Et=2n**256n-2n**32n-977n;var ot="0123456789ABCDEFGHJKMNPQRSTVWXYZ",w=new TextEncoder,it=e=>{let t="";for(let n of e)t+=String.fromCharCode(n);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")},h=e=>{let t=atob(e.replace(/-/g,"+").replace(/_/g,"/")),n=new Uint8Array(t.length);for(let r=0;r<t.length;r++)n[r]=t.charCodeAt(r);return n},C=async e=>new Uint8Array(await crypto.subtle.digest("SHA-256",e)),S=(...e)=>{let t=new Uint8Array(e.reduce((r,o)=>r+o.length,0)),n=0;for(let r of e)t.set(r,n),n+=r.length;return t};async function O(e){let t=await C(S(w.encode("pipeup-inbox/1"),h(e))),n=0,r=0,o="";for(let a of t)for(r=r<<8|a,n+=8;n>=5&&o.length<26;)o+=ot[r>>>n-5&31],n-=5;return o}var st=e=>{let t=0;for(let n of e)if(n===0)t+=8;else return t+Math.clz32(n)-24;return t};async function M(e,t,n){for(let r=0;;r++)if(st(await C(w.encode(`${e}|${t}|${r}`)))>=n)return String(r)}var at=Uint8Array.from([48,46,2,1,0,48,5,6,3,43,101,110,4,34,4,32]);async function I(e,t,n){let r=await crypto.subtle.importKey("raw",e,"HKDF",!1,["deriveBits"]);return new Uint8Array(await crypto.subtle.deriveBits({name:"HKDF",hash:"SHA-256",salt:new Uint8Array,info:w.encode(t)},r,n*8))}async function D(e){let t=await I(h(e),"pipeup-inbox/x25519",32),n=await crypto.subtle.importKey("pkcs8",S(at,t),{name:"X25519"},!0,["deriveBits"]),r=await crypto.subtle.exportKey("jwk",n);return{privateKey:n,publicKey:r.x}}var L=async(e,t)=>crypto.subtle.importKey("raw",await I(S(e,t),"pipeup-inbox/seal",32),"AES-GCM",!1,["encrypt","decrypt"]);async function _(e,t){let n=await crypto.subtle.generateKey({name:"X25519"},!0,["deriveBits"]),r=new Uint8Array(await crypto.subtle.exportKey("raw",n.publicKey)),o=await crypto.subtle.importKey("raw",h(e),{name:"X25519"},!1,[]),a=new Uint8Array(await crypto.subtle.deriveBits({name:"X25519",public:o},n.privateKey,256)),c=crypto.getRandomValues(new Uint8Array(12)),m=new Uint8Array(await crypto.subtle.encrypt({name:"AES-GCM",iv:c},await L(a,r),w.encode(t)));return`pi1.${it(S(r,c,m))}`}async function N(e,t){try{let n=h(t.replace(/^pi1\./,"")),r=n.slice(0,32),o=n.slice(32,44),a=await crypto.subtle.importKey("raw",r,{name:"X25519"},!1,[]),c=new Uint8Array(await crypto.subtle.deriveBits({name:"X25519",public:a},e.privateKey,256)),m=await crypto.subtle.decrypt({name:"AES-GCM",iv:o},await L(c,r),n.slice(44));return new TextDecoder().decode(m)}catch{return null}}async function j(e,t,n,r){try{let o=await crypto.subtle.importKey("raw",h(e),{name:"Ed25519"},!1,["verify"]);return await crypto.subtle.verify({name:"Ed25519"},o,h(r),w.encode(`pipeup:${t}
|
|
2
|
+
${n}`))}catch{return!1}}var k=class{constructor(t,n){this.base=t;this.signal=n}url(t,n=""){return`${this.base.replace(/\/+$/,"")}/i/${t}${n}`}async call(t,n,r,o={}){return fetch(n,{method:t,credentials:"omit",referrerPolicy:"no-referrer",mode:"cors",signal:this.signal,headers:{...r===void 0?{}:{"content-type":"text/plain;charset=UTF-8"},...o},body:r===void 0?void 0:JSON.stringify(r)})}async putKey(t,n,r,o){return(await this.call("PUT",this.url(t,"/key"),{ed:n,pub:r,sig:o})).ok}async getKey(t){let n=await this.call("GET",this.url(t,"/key"));return n.ok?(await n.json()).pub:null}async leave(t,n){let r=14;for(let o=0;o<2;o++){let a=await this.call("POST",this.url(t),{ct:n,work:await M(t,n,r)});if(a.ok)return!0;let c=a.status===403?(await a.json().catch(()=>({}))).bits:void 0;if(!c||c<=r||c>24)return!1;r=c}return!1}async list(t,n){let r=await this.call("GET",`${this.url(t)}${n?`?since=${n}`:""}`);if(r.status===404)return{notes:[],next:n};if(!r.ok)throw new Error("the inbox service didn't answer");return await r.json()}async remove(t,n,r,o){return(await this.call("DELETE",this.url(t,`/${n}`),void 0,{"x-pipeup-key":r,"x-pipeup-sig":o})).ok}};var F="pipeup:inbox-on",z=["M12 12a4 4 0 1 0 0-8a4 4 0 0 0 0 8z","M4 20c0-4 3.6-6 8-6s8 2 8 6"],H=/^[A-Za-z0-9_-]{43}$/,ct=()=>{try{return localStorage.getItem(F)==="1"}catch{return!1}},pt=e=>{try{localStorage.setItem(F,e?"1":"0")}catch{}};function dt(e){let t=b("data-pipeup-inbox",e)??"";try{let n=new URL(t),r=n.hostname==="localhost"||n.hostname==="127.0.0.1"||n.hostname==="[::1]";return n.protocol==="https:"||n.protocol==="http:"&&r?t:""}catch{return""}}var R=e=>JSON.stringify([e.v,e.from,e.name,e.text,e.link,e.title,e.at]),ut=e=>{try{let t=new URL(e);return t.protocol==="https:"||t.protocol==="http:"||t.protocol==="file:"?t.href:null}catch{return null}};function G(){return{id:"inbox",api:1,version:"0.7.0-beta.1",needs:["menu","notify","panel","sign"],network:{when:"after-consent",to:["the inbox service the page names (data-pipeup-inbox)"],says:"Only after you switch on Mentions by inbox: when you mention someone, a short note (who, your words, the page's address) is left for them at the page's inbox service, sealed so only they can read it; and your own inbox is checked there. The service sees that a note arrived, its size and when, and your network address, never who it is from or what it says."},setup(e){let t=dt();if(!t)return e.off('the page names no inbox service (data-pipeup-inbox="https://\u2026")');let n=new k(t,e.signal),r=e.document.me,o=Math.max(1,Number(b("data-pipeup-inbox-poll"))||60),a=ct(),c=null,m="",P=0,f=new Map,x=null,A=null,X=async()=>{if(c)return c;let s=await D(await e.sign("seed","x25519")),d=await O(r);return await n.putKey(d,r,s.publicKey,await e.sign("key",`${d}:${s.publicKey}`)),c={key:s,id:d}},U=()=>{x?.remove(),x=null,f.size&&(x=e.addMenuItem({id:"waiting",icon:z,label:()=>"Mentions waiting",hint:()=>"People who mentioned you, on pages you may not have opened",count:()=>String(f.size),select:J}))},J=()=>{let s=document.createElement("div"),d=()=>{s.replaceChildren(),f.size||s.append(Object.assign(document.createElement("p"),{textContent:"Nothing waiting."}));for(let p of f.values()){let i=document.createElement("div");i.append(Object.assign(document.createElement("strong"),{textContent:`${p.name||"Someone"} mentioned you`}),Object.assign(document.createElement("p"),{textContent:p.text}),Object.assign(document.createElement("small"),{textContent:`${p.title} \xB7 ${p.link}`}));let y=ut(p.link),l=document.createElement("div");if(y){let g=Object.assign(document.createElement("button"),{type:"button",textContent:"Open the page"});g.addEventListener("click",()=>window.open(y,"_blank","noopener,noreferrer")),l.append(g)}let u=Object.assign(document.createElement("button"),{type:"button",textContent:"Dismiss"});u.addEventListener("click",()=>void Z(p.id).then(d)),l.append(u),i.append(l),s.append(i)}};d(),A=e.openPanel(s,{label:"Mentions waiting",onClose:()=>A=null})},Z=async s=>{c&&(await n.remove(c.id,s,r,await e.sign("delete",`${c.id}:${s}`))&&f.delete(s),U())},K=async()=>{try{let s=await X(),d=await n.list(s.id,m);m=d.next;let p=0;for(let{id:i,ct:y}of d.notes){let l=await N(s.key,y);if(!(!l||f.has(i)))try{let[u,g]=JSON.parse(l);if(u.v!==1||!H.test(u.from)||!await j(u.from,"inbox/note",R(u),g))continue;f.set(i,{...u,id:i}),p++}catch{}}p&&(U(),e.notify(`${p} new mention${p===1?"":"s"} waiting`))}catch{}},W=async s=>{let d=s.text??"",p=[...new Set((s.mentions??[]).map(i=>i.ref).filter(i=>H.test(i)&&i!==r))];for(let i of p)try{let y=await O(i),l=await n.getKey(y);if(!l)continue;let u={v:1,from:r,name:e.document.name,text:d,link:location.href,title:document.title,at:Date.now()},g=await e.sign("note",R(u));await n.leave(y,await _(l,JSON.stringify([u,g])))}catch{}},$=()=>{K(),P=window.setInterval(()=>!document.hidden&&void K(),o*1e3)},q=()=>{window.clearInterval(P),f.clear(),U(),A?.close()},V=e.addMenuItem({id:"inbox",icon:z,label:()=>"Mentions by inbox",hint:()=>`Leaves a sealed note for people you mention, at ${new URL(t).host}, and checks your own inbox there. The service sees that a note arrived, its size and when, and your network address, never who it is from or what it says.`,checked:()=>a,select:()=>{a=!a,pt(a),a?$():q()}}),Y=e.document.onChange((s,d,p)=>{if(!(!a||p!=="local"))for(let{body:i}of d)i.author===r&&i.mentions?.length&&(i.kind==="create"||i.kind==="reply")&&W(i)});return a&&$(),()=>{Y(),window.clearInterval(P),V.remove(),x?.remove(),A?.close()}}}}B(G());})();
|