{"version":3,"sources":["core/bytes.ts","core/consts.ts","lib/crypto.ts","core/crypto.ts","lib/db.ts","core/pow.ts","core/challenge.ts","lib/net.ts","core/client/net.ts","core/client/api.ts","lib/api.ts","lib/eventBus.ts","models/host.ts","models/state.ts","models/id.ts","models/message.ts","models/reply.ts","lib/storage.ts","core/client/lib.ts","lib/auth.ts","core/client/creds.ts","models/user.ts","models/profile.ts","components/access.tsx","components/hexatar.tsx","components/hexQR.tsx","components/timestamp.tsx","components/textPost.tsx","components/codePost.tsx","components/postContent.tsx","components/post.tsx","models/post.ts","components/encryptedPost.tsx","components/replyButton.tsx","components/postList.tsx","components/empty.tsx","components/hexIdCard.tsx","components/subscriberList.tsx","components/subscribeView.tsx","components/subscriptionList.tsx","components/tabs.tsx","components/knowMore.tsx","components/repliesList.tsx","components/profile.tsx","pages/App.tsx","reportWebVitals.ts","components/credFields.tsx","pages/loadCreds.tsx","models/inbox.ts","pages/dumpCreds.tsx","pages/userProfile.tsx","pages/post.tsx","pages/exit.tsx","pages/sub.tsx","pages/subArch.tsx","pages/postArch.tsx","pages/arch.tsx","pages/host.tsx","pages/feed.tsx","pages/postDetails.tsx","pages/dataArch.tsx","components/subscriptionRequest.tsx","components/inboxItem.tsx","pages/inbox.tsx","pages/api.tsx","index.tsx"],"names":["hex2bytes","hex","length","numBytes","bytes","Uint8Array","b","i","pair","slice","x","parseInt","bytes2hex","Array","from","map","h","toString","toUpperCase","join","buf2hex","buf","concatArrayBuffers","buf1","buf2","buf1Bytes","buf2Bytes","combined","set","NUM_SIG_BYTES","ecdsaParams","name","hash","tokenHeader","pubKeyHeader","sigHeader","powHeader","crypto","numIvBytes","this","a","subtle","generateKey","namedCurve","publicKey","privateKey","usages","deriveKey","public","pubKey","exportKey","dump","importKey","signerPubKey","sig","data","verify","ecdsaPrivKey","sign","key","digest","plaintext","rawKey","sha","iv","genIV","encrypt","ciphertext","payload","TextEncoder","encode","encryptBuf","decrypt","decrypted","decryptBuf","TextDecoder","decode","window","DB","subscriptions","followers","posts","postKeys","indexes","profiles","version","stores","Dexie","wipeDB","delete","open","dumpState","toArray","following","loadStateDangerously","state","transaction","Promise","all","clear","bulkAdd","inc","arr","PoW","num","N","totalBits","byteLength","numZeroBits","numRemainderBits","numZeroBytes","seed","candidate","test","lessThan2ToN","numHashBytes","getRandomValues","solve","numHashBits","console","log","solvePoWChallenge","chal","diff","pow","solution","hostPrefix","process","fetch","npCrypto","pubKeyHex","path","id","location","fileLoc","getFile","posterPubKeyHex","postKeyLocHex","host","getFileSignedJSON","postHashHex","method","headers","Accept","resp","ok","arrayBuffer","token","signerPubKeyHex","status","hex2ECDSAKey","rest","json","index","JSON","parse","error","contentType","sigHex","body","inbox","pubPubKeyHex","ephemDHPubBuf","encMsgBuf","powSolution","ephemDHPubBytes","ephemDHPubHex","powHex","capDesc","stringify","text","Error","solutionHex","chalResp","bind","NPCrypto","API","net","post","postKey","privKey","encryptString","now","Date","toISOString","updatedAt","getIndex","idx","hashHex","putFile","push","indexEnc","indexSig","signedIndex","signPrivKey","postHash","encKey","postKeyLocation","locHex","key2buf","postKeyRaw","postKeyHex","outerKey","encKeyBytes","locBytes","rawPubKey","type","fetchAuthChallenge","pubKeyBuf","fetchSessionToken","fetchAndDecryptPostWithOuterKey","encBuf","Net","fetchPostKey","postKeyEncBytes","Crypto","decryptString","postKeyBytes","importAESKey","decKey","postJson","fetchAndDecryptPostWithSubKey","privDH","hex2ECDHKey","pubECDH","deriveDHKey","fetchAndDecryptPost","worldKeyHex","outerKeyBytes","fetchAndDecryptWorldOrSubPost","fetchPost","worldPost","subPost","publishPostAndKeys","visibility","genSymmetricKey","publishPost","newIndex","add","publisherPubKey","publishPostWorldKey","getSubscriberPubKeyList","subs","subPubKeys","sub","targetPubKeys","concat","promises","subPubKey","publishPostSubKey","worldKeyBytes","worldKey","keyLoc","put","publishPostKey","subDHPub","encDH","sendSubRequest","subPubKeyHex","msg","destHost","srcHost","message","sendMessage","api","getUserAuthChallenge","getMessageAuthChallenge","getSessionToken","EventBus","listeners","Set","l","forEach","getToken","setStatus","putState","loadID","ident","stateKeyHex","getStateKey","stateKeyBytes","stateKey","fetchState","getPublicKeyHex","loc","mutateState","mutateFn","IdentityContext","createContext","undefined","getPublicKey","getPrivateKey","getWorldKey","dhKey","idChange","identify","creds","loadCreds","Host","setToken","fetchAndStoreOwnProfile","emit","deidentify","localStorage","storeCredentials","idKeys","setIDKeys","setWorldKey","setStateKey","ephemDHPub","ephemDH","fetchInboxItem","enc","decBuf","destPubKeyHex","userPubKey","msgJson","msgBuf","signed","pubECDSA2ECDH","genECDHKeys","ephemKeys","encReqBuf","putMessage","sendReply","postId","senderPubKeyHex","createdAt","recordReplyInDB","replyId","reply","pubJWK","privJWK","getPrivateKeyJWK","getPublicKeyJWK","addSubscriptionPubKey","handle","catch","e","stateJSON","replyToHash","content","json2hex","json2key","raw","keyType","jwk","key_ops","isAuthenticated","usage","loadFromJSON","worldKeyBufResult","stateKeyBufResult","AuthorizedUser","user","profile","pubKeyResult","storeProfile","uploadProfile","User","worldKeyBuf","genIDKeyPair","fetchProfile","userId","loadProfile","get","useProfile","useState","setProfile","newProfile","useEffect","local","remote","then","p","followsMe","bio","createProfile","create","authedUser","storeCreds","storeAndUploadProfile","follow","acceptFollower","addSubscriber","req","Access","navigate","useNavigate","next","useLocation","search","className","src","alt","to","href","onClick","colors","Hexatar","rows","r","start","cols","c","lastChar","borderColor","style","row","char","color","HexQR","QR","QRCode","fgColor","value","bgColor","size","level","Timestamp","ts","date","isToday","toLocaleDateString","dateOpts","year","getFullYear","month","day","timeOpts","hour","minute","second","str","Intl","DateTimeFormat","format","TextPost","CodePost","code","PostContent","Contents","Post","loadPosts","orderBy","reverse","fetchAndCachePost","res","publishTextPost","cachePost","postRow","viewerPubKey","hashBuf","deleteFile","alert","EncryptedPost","useContext","setPost","fetchAndDec","ViewReplyButton","setId","ReplyButton","replyState","setReplyState","sentReply","setSentReply","encodeURIComponent","pathname","prompt","replyMsg","handleReply","disabled","PostList","empty","showReply","Empty","subtext","MissingHandle","HexIDCard","link","escape","SubscriberItem","SubscriberList","setSubs","fetchSubs","filter","err","useSubscribers","Object","values","SubscribeView","url","setURL","match","RegExp","exec","evt","preventDefault","stopPropagation","unescape","getProfile","onSubmit","onChange","target","placeholder","SubscriptionItem","SubscriptionList","TabBar","tabs","activeTab","onTabSelected","tab","isActive","textUnderlineOffset","Tabs","initialActiveTab","setActiveTab","activeEl","el","t","KnowMore","more","label","showMore","setShowMore","RepliesList","replies","setReplies","where","and","repls","useReplies","BracketButton","ButtonLink","Handle","setHandle","editable","newHandle","Bio","setBio","newBio","IDCard","isAuthedUser","Profile","URLSearchParams","isSubscribed","setIsSubscribed","useIsSubscribedTo","setIndex","remoteIndex","load","useIndex","emptyPostList","document","App","reportWebVitals","onPerfEntry","Function","getCLS","getFID","getFCP","getLCP","getTTFB","CredFields","fixedCreds","ctaText","submitEnabledManualOverride","idFieldRef","useRef","credFieldRef","setID","setCreds","submitDisabled","isLoading","action","htmlFor","ref","autoComplete","LoadCreds","More","reveal","setReveal","credState","setCredState","blob","Blob","saveAs","replace","readOnly","CredDumper","nextURL","username","DumpCreds","UserProfile","useParams","setText","viz","setViz","handlePostClicked","Exit","manualOverride","setManualOverride","exit","credsMatch","checked","Sub","sentReq","setSentReq","pubId","setFollowing","SubArch","PostArch","Arch","Feed","setPosts","loading","setLoading","fetchPosts","AudienceListItem","removeAccess","Audience","pubKeys","setPubKeys","useAudience","PostDetails","rs","postHost","isPoster","deletePost","DataArch","inboxChange","loadInbox","force","fetchInbox","newInbox","InboxContext","deleteInboxItem","acceptRequest","Req","InboxItem","item","setItem","unwrapInboxItem","Inbox","Endpoint","endpoint","desc","request","spec","MenuItem","curPath","highlight","authedMenu","count","showCount","unauthedMenu","Menu","items","kbLink","width","props","Main","reloadID","on","off","useID","setInbox","reloadInbox","inb","useInbox","StrictMode","Provider","element","ReactDOM","render","getElementById"],"mappings":"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","file":"static/js/main.a891e84b.chunk.js","sourcesContent":["export function hex2bytes(hex: string): Uint8Array | null {\n if (hex.length % 2 !== 0) {\n return null;\n }\n\n const numBytes = hex.length / 2;\n const bytes = new Uint8Array(numBytes);\n\n for (let b = 0; b < numBytes; b++) {\n const i = b * 2;\n const pair = hex.slice(i, i + 2);\n const x = parseInt(pair, 16);\n bytes[b] = x;\n }\n\n return bytes;\n}\n\nexport function bytes2hex(bytes: Uint8Array): string {\n const hex: string[] = Array.from(bytes).map((b) => {\n const h = b.toString(16).toUpperCase();\n if (h.length < 2) {\n return `0${h}`;\n }\n return h;\n });\n\n return hex.join(\"\");\n}\n\nexport function buf2hex(buf: ArrayBuffer): string {\n const bytes = new Uint8Array(buf);\n return bytes2hex(bytes);\n}\n\nexport function concatArrayBuffers(\n buf1: ArrayBuffer,\n buf2: ArrayBuffer,\n): ArrayBuffer {\n const buf1Bytes = new Uint8Array(buf1);\n const buf2Bytes = new Uint8Array(buf2);\n\n const combined = new Uint8Array(buf1Bytes.length + buf2Bytes.length);\n combined.set(buf1Bytes, 0);\n combined.set(buf2Bytes, buf1Bytes.length);\n\n return combined;\n}\n","export const POW_DIFF = 14;\n\nexport const NUM_SIG_BYTES = 64;\nexport const ECDSA_PUBKEY_BYTES = 65;\nexport const SOLUTION_BYTES = 32;\nexport const SIGNATURE_BYTES = 64;\nexport const ecdsaParams: EcdsaParams = { name: \"ECDSA\", hash: \"SHA-256\" };\n\nexport const tokenHeader = \"neopub-token\";\nexport const pubKeyHeader = \"neopub-pub-key\";\nexport const sigHeader = \"neopub-sig\";\nexport const postKeyHeader = \"neopub-post-key\";\nexport const subDhKey = \"neopub-sub-key\";\nexport const powHeader = \"neopub-pow\";\n","import Crypto from \"core/crypto\";\n\nexport default new Crypto(window.crypto);\n","import { concatArrayBuffers, hex2bytes } from \"./bytes\";\nimport { ecdsaParams } from \"./consts\";\n\nexport default class NPCrypto {\n crypto: Crypto;\n constructor(crypto: Crypto) {\n this.crypto = crypto;\n }\n\n async genIDKeyPair(): Promise {\n return this.crypto.subtle.generateKey(\n { name: \"ECDSA\", namedCurve: \"P-256\" },\n true,\n [\"sign\", \"verify\"],\n );\n }\n\n async deriveDHKey(\n publicKey: CryptoKey,\n privateKey: CryptoKey,\n usages: KeyUsage[],\n ): Promise {\n return this.crypto.subtle.deriveKey(\n { name: \"ECDH\", public: publicKey },\n privateKey,\n { name: \"AES-CBC\", length: 256 },\n true,\n usages,\n );\n }\n\n async pubECDSA2ECDH(pubKey: CryptoKey): Promise {\n // HACK: dump ECDSA pub key and load it as an ECDH pub key.\n // This is only used 1-way, for a subscriber to send a request to the pub key's owner.\n // Is this a problem?\n const dump = await this.crypto.subtle.exportKey(\"jwk\", pubKey);\n return await this.crypto.subtle.importKey(\n \"jwk\",\n dump,\n { name: \"ECDH\", namedCurve: \"P-256\" },\n true,\n [],\n );\n }\n\n async genECDHKeys(): Promise {\n return this.crypto.subtle.generateKey(\n { name: \"ECDH\", namedCurve: \"P-256\" },\n true,\n [\"deriveKey\"],\n );\n }\n\n async verify(signerPubKey: CryptoKey, sig: ArrayBuffer, data: ArrayBuffer) {\n return this.crypto.subtle.verify(\n ecdsaParams,\n signerPubKey,\n sig,\n data,\n );\n }\n\n async importAESKey(\n buf: ArrayBuffer,\n usages: KeyUsage[],\n ): Promise {\n return this.crypto.subtle.importKey(\"raw\", buf, { name: \"AES-CBC\" }, true, usages);\n }\n\n async hex2ECDHKey(hex: string): Promise {\n const bytes = hex2bytes(hex);\n if (!bytes) {\n return;\n }\n return this.crypto.subtle.importKey(\n \"raw\",\n bytes,\n { name: \"ECDH\", namedCurve: \"P-256\" },\n true,\n [],\n );\n }\n\n async hex2ECDSAKey(\n hex: string,\n ): Promise {\n const bytes = hex2bytes(hex);\n if (!bytes) {\n return;\n }\n return this.crypto.subtle.importKey(\n \"raw\",\n bytes,\n { name: \"ECDSA\", namedCurve: \"P-256\" },\n true,\n [\"verify\"],\n );\n }\n\n async sign(\n ecdsaPrivKey: CryptoKey,\n bytes: ArrayBuffer,\n ): Promise {\n return this.crypto.subtle.sign(\n { name: \"ECDSA\", hash: \"SHA-256\" },\n ecdsaPrivKey,\n bytes,\n );\n }\n\n async key2buf(key: CryptoKey): Promise {\n return this.crypto.subtle.exportKey(\"raw\", key);\n }\n\n async sha(data: ArrayBuffer): Promise {\n return this.crypto.subtle.digest(\"SHA-256\", data);\n }\n\n async genSymmetricKey(): Promise {\n // Generate a new key.\n const key = await this.crypto.subtle.generateKey(\n {\n name: \"AES-CBC\",\n length: 256,\n },\n true,\n [\"encrypt\", \"decrypt\"],\n );\n return key;\n }\n\n numIvBytes = 16;\n\n async genIV(\n plaintext: ArrayBuffer,\n key: CryptoKey,\n ): Promise {\n const rawKey = await this.crypto.subtle.exportKey(\"raw\", key);\n\n const combined = concatArrayBuffers(rawKey, plaintext);\n\n const sha = await this.crypto.subtle.digest(\"SHA-256\", combined);\n const iv = sha.slice(0, this.numIvBytes);\n\n return iv;\n }\n\n async encryptBuf(plaintext: ArrayBuffer, key: CryptoKey): Promise {\n const iv = await this.genIV(plaintext, key);\n\n const ciphertext = await this.crypto.subtle.encrypt(\n {\n name: \"AES-CBC\",\n iv,\n },\n key,\n plaintext,\n );\n\n const payload = concatArrayBuffers(iv, ciphertext);\n return payload;\n }\n\n async encryptString(\n data: string,\n key: CryptoKey,\n ): Promise {\n const plaintext = new TextEncoder().encode(data);\n return this.encryptBuf(plaintext, key);\n }\n\n async decryptBuf(\n payload: ArrayBuffer,\n key: CryptoKey,\n ): Promise {\n const bytes = new Uint8Array(payload);\n const iv = bytes.slice(0, this.numIvBytes);\n const ciphertext = bytes.slice(this.numIvBytes);\n\n const decrypted = await this.crypto.subtle.decrypt(\n {\n name: \"AES-CBC\",\n iv,\n },\n key,\n ciphertext,\n );\n\n return decrypted;\n }\n\n async decryptString(\n payload: ArrayBuffer,\n key: CryptoKey,\n ): Promise {\n const decrypted = await this.decryptBuf(payload, key);\n const plaintext = new TextDecoder().decode(decrypted);\n return plaintext;\n }\n}","import { IIndex, TPost } from \"core/types\";\nimport Dexie from \"dexie\";\n\ninterface IDBSubscription {\n pubKey: string;\n host: string;\n worldKeyHex: string;\n handle?: string;\n}\n\ninterface IDBFollower {\n pubKey: string;\n host: string;\n}\n\ninterface IDBPost {\n hash: string;\n publisherPubKey: string;\n // createdAt: Date;\n post: TPost;\n replyToHash?: string;\n}\n\ninterface IDBPostKey {\n keyLoc: string;\n postHash: string;\n subPubKey: string;\n}\n\ninterface IDBIndex {\n pubKey: string;\n index: IIndex;\n // updatedAt: Date;\n}\n\ninterface IDBProfile {\n pubKey: string;\n host?: string;\n worldKey: string;\n handle?: string;\n bio?: string;\n following: boolean;\n followsMe: boolean;\n}\nclass NeoPubDexie extends Dexie {\n subscriptions!: Dexie.Table;\n followers!: Dexie.Table;\n posts!: Dexie.Table;\n postKeys!: Dexie.Table;\n indexes!: Dexie.Table;\n profiles!: Dexie.Table;\n\n constructor() {\n super(\"neopub\");\n\n this.version(11).stores({\n subscriptions: \"pubKey\",\n followers: \"pubKey\",\n posts: \"hash, publisherPubKey, createdAt, replyToHash\",\n postKeys: \"postHash\", // TODO: record post key and derive location instead?\n indexes: \"pubKey\",\n profiles: \"pubKey\",\n });\n }\n}\n\nconst DB = new NeoPubDexie();\n\nexport async function wipeDB() {\n await DB.delete();\n return DB.open();\n}\n\ninterface ILocalState {\n following: IDBSubscription[];\n followers: IDBFollower[];\n profiles: IDBProfile[];\n}\n\nexport async function dumpState(): Promise {\n const following = await DB.subscriptions.toArray();\n const followers = await DB.followers.toArray();\n const profiles = await DB.profiles.toArray();\n return { followers, following, profiles };\n}\n\nexport async function loadStateDangerously(state: ILocalState) {\n const { followers, following, profiles } = state;\n \n DB.transaction(\"rw\", [DB.subscriptions, DB.followers, DB.profiles], async () => {\n return Promise.all([\n DB.subscriptions.clear(),\n DB.subscriptions.bulkAdd(following),\n DB.followers.clear(),\n DB.followers.bulkAdd(followers),\n DB.profiles.clear(),\n DB.profiles.bulkAdd(profiles),\n ]);\n });\n}\n\nexport default DB;","const bitsPerByte = 8;\nconst numHashBytes = 32; // SHA-256\nexport const numHashBits = numHashBytes * bitsPerByte;\n\nexport function inc(arr: Uint8Array) {\n for (let i = arr.length - 1; i >= 0; i--) {\n if (arr[i] < 0xff) {\n arr[i] += 1;\n return;\n }\n\n arr[i] = 0;\n }\n\n return -1;\n}\n\nexport default class PoW {\n crypto;\n constructor(crypto: any) {\n this.crypto = crypto;\n }\n\n public lessThan2ToN(num: Uint8Array, N: number): boolean {\n const totalBits = num.byteLength * bitsPerByte;\n if (N >= totalBits) {\n return true;\n }\n\n const numZeroBits = totalBits - N;\n const numRemainderBits = numZeroBits % 8;\n const numZeroBytes = (numZeroBits - numRemainderBits) / 8;\n\n let i: number;\n for (i = 0; i < numZeroBytes; i++) {\n if (num[i] !== 0) {\n return false;\n }\n }\n\n if (numRemainderBits !== 0) {\n const x = 0x1 << (8 - numRemainderBits);\n return num[i] < x;\n }\n\n return true;\n }\n\n async solve(seed: Uint8Array, N: number) {\n // Goal, find key s.t. sha256(seed ++ key) < 2**N.\n\n // Brute-force search all possible key values.\n const numBytes = 32;\n const candidate = new Uint8Array(numBytes);\n\n while (inc(candidate) !== -1) {\n const test = await this.hash(candidate, seed);\n if (this.lessThan2ToN(test, N)) {\n return candidate;\n }\n }\n\n return null;\n }\n\n async hash(key: Uint8Array, seed: Uint8Array) {\n const test = new Uint8Array(key.length + seed.length);\n test.set(seed, 0);\n test.set(key, seed.length);\n\n const hash = await this.crypto.subtle.digest(\"SHA-256\", test);\n return new Uint8Array(hash);\n }\n\n async test() {\n const numHashBits = numHashBytes * bitsPerByte;\n\n const difficulty = 14;\n\n const seed = this.crypto.getRandomValues(new Uint8Array(16));\n\n const solution = await this.solve(seed, numHashBits - difficulty);\n if (!solution) {\n console.log(\"No solution found.\");\n return;\n }\n\n // const solh = await this.hash(solution, seed);\n // console.log({ seed, solution, solh });\n }\n}\n","import PoW, { numHashBits } from \"./pow\";\n\nexport default async function solvePoWChallenge(\n chal: Uint8Array,\n diff: number,\n): Promise {\n const pow = new PoW(crypto);\n const solution = await pow.solve(chal, numHashBits - diff);\n return solution;\n}\n","import Net from \"core/client/net\";\nimport NPCrypto from \"lib/crypto\";\n\nexport const hostPrefix = process.env.REACT_APP_HOST_PREFIX ?? \"NOHOST\";\n\nexport default new Net(hostPrefix, fetch.bind(window), NPCrypto);\n","import { pubKeyHeader, tokenHeader, sigHeader, subDhKey, powHeader, NUM_SIG_BYTES } from \"../consts\";\nimport { buf2hex, bytes2hex, hex2bytes } from \"../bytes\";\nimport { IAuthChallenge, IIndex, IProfile, NotFound, CapabilityDescription } from \"../types\";\nimport NPCrypto from \"../crypto\";\n\ntype FetchFn = (input: string, init?: { method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\", headers?: Record, body?: any }) => Promise;\n\nexport default class Net {\n hostPrefix: string;\n fetch: FetchFn;\n npCrypto: NPCrypto;\n\n constructor(hostPrefix: string, fetch: FetchFn, npCrypto: NPCrypto) {\n this.hostPrefix = hostPrefix;\n this.fetch = fetch;\n this.npCrypto = npCrypto;\n }\n\n fileLoc(pubKeyHex: string, path: string): string {\n return `/users/${pubKeyHex}/${path}`;\n }\n\n async fetchInboxItem(\n pubKeyHex: string,\n id: string,\n ): Promise {\n const location = this.fileLoc(pubKeyHex, `inbox/${id}`);\n return this.getFile(location);\n }\n\n async fetchPostKey(\n posterPubKeyHex: string,\n postKeyLocHex: string,\n ): Promise {\n const location = this.fileLoc(posterPubKeyHex, `keys/${postKeyLocHex}`);\n return this.getFile(location);\n }\n\n async getIndex(pubKeyHex: string, host?: string): Promise {\n const location = this.fileLoc(pubKeyHex, \"index.json\");\n return this.getFileSignedJSON(pubKeyHex, location, host);\n }\n\n async getProfile(pubKeyHex: string, host?: string): Promise {\n const location = this.fileLoc(pubKeyHex, \"profile.json\");\n return this.getFileSignedJSON(pubKeyHex, location, host);\n }\n\n async fetchPost(\n posterPubKeyHex: string,\n postHashHex: string,\n ): Promise {\n const location = this.fileLoc(posterPubKeyHex, `posts/${postHashHex}`);\n return this.getFile(location);\n }\n\n async getFile(location: string): Promise {\n try {\n const resp = await this.fetch(`${this.hostPrefix}${location}`, {\n method: \"GET\",\n headers: {\n Accept: \"application/octet-stream\",\n },\n });\n if (!resp.ok) {\n return;\n }\n const buf = resp.arrayBuffer();\n return buf\n } catch {\n return\n }\n }\n\n async deleteFile(pubKeyHex: string, token: string, location: string): Promise {\n return this.fetch(`${this.hostPrefix}${location}`, {\n method: \"DELETE\",\n headers: {\n Accept: \"application/octet-stream\",\n [pubKeyHeader]: pubKeyHex,\n [tokenHeader]: token,\n },\n });\n }\n\n async getFileSignedJSON(signerPubKeyHex: string, location: string, host?: string): Promise {\n try {\n const resp = await this.fetch(`${host ?? this.hostPrefix}${location}`, {\n method: \"GET\",\n headers: {\n Accept: \"application/json\",\n },\n });\n if (resp.status === 404) {\n return \"notfound\";\n }\n if (!resp.ok) {\n return;\n }\n\n const buf = await resp.arrayBuffer();\n const sig = buf.slice(0, NUM_SIG_BYTES);\n\n // TODO: check.\n const signerPubKey = await this.npCrypto.hex2ECDSAKey(signerPubKeyHex);\n if (!signerPubKey) {\n return; // TODO: signal error.\n }\n\n const rest = buf.slice(NUM_SIG_BYTES);\n\n const valid = await this.npCrypto.verify(signerPubKey, sig, rest);\n if (!valid) {\n return; // TODO blow up.\n }\n\n const json = new TextDecoder().decode(rest);\n const index = JSON.parse(json);\n\n return index;\n } catch (err) {\n console.error(err);\n return;\n }\n }\n\n async putFile(\n location: string,\n pubKeyHex: string,\n token: string,\n payload: ArrayBuffer,\n sig: ArrayBuffer,\n contentType: \"application/json\" | \"application/octet-stream\",\n ): Promise {\n const sigHex = bytes2hex(new Uint8Array(sig));\n\n await this.fetch(`${this.hostPrefix}${location}`, {\n method: \"PUT\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": contentType,\n [pubKeyHeader]: pubKeyHex,\n [tokenHeader]: token,\n [sigHeader]: sigHex,\n },\n body: payload,\n });\n }\n\n async fetchInbox(pubKey: string, token: string): Promise {\n const resp = await this.fetch(`${this.hostPrefix}/inbox`, {\n method: \"GET\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n [pubKeyHeader]: pubKey,\n [tokenHeader]: token,\n },\n });\n try {\n const inbox = await resp.json();\n return inbox;\n } catch {\n return []\n }\n }\n\n async putMessage(\n pubPubKeyHex: string,\n ephemDHPubBuf: ArrayBuffer,\n encMsgBuf: ArrayBuffer,\n powSolution: Uint8Array,\n host?: string,\n ): Promise {\n const ephemDHPubBytes = new Uint8Array(ephemDHPubBuf);\n const ephemDHPubHex = bytes2hex(ephemDHPubBytes);\n\n const powHex = bytes2hex(powSolution);\n\n await this.fetch(`${host ?? this.hostPrefix}/inbox`, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n [pubKeyHeader]: pubPubKeyHex,\n [subDhKey]: ephemDHPubHex,\n [powHeader]: powHex,\n },\n body: encMsgBuf,\n });\n }\n\n async fetchAuthChallenge(\n capDesc: CapabilityDescription,\n host?: string,\n ): Promise {\n const resp = await this.fetch(`${host ?? this.hostPrefix}/auth`, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(capDesc),\n });\n const bytes = hex2bytes(await resp.text());\n if (!bytes) {\n throw new Error('failed to parse hex');\n }\n const diff = bytes[bytes.length - 1];\n const chal = bytes.slice(0, bytes.length - 1);\n\n return { chal, diff };\n }\n\n async fetchSessionToken(\n pubKey: ArrayBuffer,\n sig: ArrayBuffer,\n solution: Uint8Array,\n ): Promise {\n const pubKeyHex = buf2hex(pubKey);\n const sigHex = bytes2hex(new Uint8Array(sig));\n\n const solutionHex = buf2hex(solution);\n\n const chalResp = await this.fetch(`${this.hostPrefix}/chal`, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/octet-stream\",\n [pubKeyHeader]: pubKeyHex,\n [sigHeader]: sigHex,\n },\n body: solutionHex,\n });\n return await chalResp.text();\n }\n}","import { buf2hex, concatArrayBuffers } from \"../bytes\";\nimport NPCrypto from \"../crypto\";\nimport { TPost, IIndex, IAuthChallenge } from \"../types\";\nimport Net from \"./net\";\n\nexport default class API {\n net: Net;\n crypto: NPCrypto;\n\n constructor(net: Net, crypto: NPCrypto) {\n this.net = net;\n this.crypto = crypto;\n }\n\n async publishPost(\n post: TPost,\n postKey: CryptoKey,\n pubKey: string,\n privKey: CryptoKey,\n token: string,\n ): Promise<[IIndex, ArrayBuffer]> {\n const body = JSON.stringify(post);\n const ciphertext = await this.crypto.encryptString(body, postKey);\n\n const now = new Date().toISOString();\n\n let index: IIndex = { posts: [], updatedAt: now };\n const idx = await this.net.getIndex(pubKey);\n if (idx && idx !== \"notfound\") {\n index = idx;\n }\n\n // Compute content-based ID.\n const hash = await this.crypto.sha(ciphertext);\n const hashHex = await buf2hex(hash);\n\n // Put post.\n await this.putFile(pubKey, `posts/${hashHex}`, privKey, token, ciphertext, \"application/octet-stream\");\n\n // Update index.\n index.posts.push({ id: hashHex });\n index.updatedAt = now;\n const indexEnc = new TextEncoder().encode(JSON.stringify(index));\n const indexSig = await this.crypto.sign(privKey, indexEnc);\n const signedIndex = concatArrayBuffers(indexSig, indexEnc);\n // putFile already signs the file for the host to check. Redundant? Cleaner way?\n\n await this.putFile(pubKey, `index.json`, privKey, token, signedIndex, \"application/json\");\n\n return [index, hash];\n }\n\n async putFile(\n pubKeyHex: string,\n path: string,\n signPrivKey: CryptoKey,\n token: string,\n data: ArrayBuffer,\n contentType: \"application/json\" | \"application/octet-stream\",\n ): Promise {\n // Sign.\n const sig = await this.crypto.sign(signPrivKey, data);\n \n // Send.\n const location = this.net.fileLoc(pubKeyHex, path);\n this.net.putFile(location, pubKeyHex, token, data, sig, contentType)\n }\n\n async publishPostKey(\n postKey: CryptoKey,\n postHash: ArrayBuffer,\n encKey: CryptoKey,\n pubKey: string,\n privKey: CryptoKey,\n token: string,\n ): Promise {\n const locHex = await this.postKeyLocation(encKey, postHash);\n \n const postKeyRaw = await this.crypto.key2buf(postKey);\n const postKeyHex = buf2hex(postKeyRaw);\n const ciphertext = await this.crypto.encryptString(postKeyHex, encKey);\n \n return this.putFile(pubKey, `keys/${locHex}`, privKey, token, ciphertext, \"application/json\");\n }\n\n async postKeyLocation(\n outerKey: CryptoKey,\n postHash: ArrayBuffer,\n ): Promise {\n const encKeyBytes = await this.crypto.key2buf(outerKey);\n const locBytes = await this.crypto.sha(concatArrayBuffers(encKeyBytes, postHash)); // TODO: don't stick post hash on end of this... that makes it trivial to analyze number of distinct posts and people with access to each.\n const locHex = buf2hex(locBytes);\n return locHex;\n }\n\n async getUserAuthChallenge(\n publicKey: CryptoKey,\n ): Promise {\n const rawPubKey = await this.crypto.key2buf(publicKey);\n const pubKeyHex = buf2hex(rawPubKey);\n const capDesc = {\n type: \"user\",\n pubKey: pubKeyHex,\n } as const;\n return this.net.fetchAuthChallenge(capDesc);\n }\n\n async getSessionToken(\n privateKey: CryptoKey,\n publicKey: CryptoKey,\n solution: Uint8Array,\n ): Promise {\n const pubKeyBuf = await this.crypto.key2buf(publicKey);\n const sig = await this.crypto.sign(privateKey, solution);\n return this.net.fetchSessionToken(pubKeyBuf, sig, solution);\n }\n}","import { hex2bytes, buf2hex } from \"core/bytes\";\nimport Crypto from \"lib/crypto\";\nimport {\n TPost,\n IIndex,\n PostVisibility,\n IAuthChallenge,\n ISubReq,\n} from \"core/types\";\nimport { getSubscriberPubKeyList } from \"lib/storage\";\nimport Net from \"lib/net\";\nimport DB from \"./db\";\nimport { sendMessage } from \"models/message\";\nimport API from \"core/client/api\";\n\nasync function fetchAndDecryptPostWithOuterKey(\n posterPubKeyHex: string,\n outerKey: CryptoKey,\n encBuf: ArrayBuffer,\n postHash: Uint8Array,\n): Promise {\n const postKeyLocHex = await postKeyLocation(outerKey, postHash);\n const postKeyEncBytes = await Net.fetchPostKey(posterPubKeyHex, postKeyLocHex);\n if (!postKeyEncBytes) {\n return;\n }\n\n const postKeyHex = await Crypto.decryptString(postKeyEncBytes, outerKey);\n const postKeyBytes = hex2bytes(postKeyHex);\n if (!postKeyBytes) {\n return;\n }\n\n const decKey = await Crypto.importAESKey(postKeyBytes, [\"decrypt\"]);\n const postJson = await Crypto.decryptString(encBuf, decKey);\n const post = JSON.parse(postJson);\n return post;\n}\n\nasync function fetchAndDecryptPostWithSubKey(\n privDH: CryptoKey,\n posterPubKeyHex: string,\n encBuf: ArrayBuffer,\n postHash: Uint8Array,\n) {\n const pubECDH = await Crypto.hex2ECDHKey(posterPubKeyHex);\n if (!pubECDH) {\n return;\n }\n\n const outerKey = await Crypto.deriveDHKey(pubECDH, privDH, [\"decrypt\"]);\n\n return fetchAndDecryptPostWithOuterKey(\n posterPubKeyHex,\n outerKey,\n encBuf,\n postHash,\n );\n}\n\nasync function fetchAndDecryptPost(\n posterPubKeyHex: string,\n worldKeyHex: string,\n encBuf: ArrayBuffer,\n postHash: Uint8Array,\n) {\n const outerKeyBytes = hex2bytes(worldKeyHex);\n if (!outerKeyBytes) {\n return;\n }\n const outerKey = await Crypto.importAESKey(outerKeyBytes, [\"decrypt\"]);\n\n return fetchAndDecryptPostWithOuterKey(\n posterPubKeyHex,\n outerKey,\n encBuf,\n postHash,\n );\n}\n\nexport async function fetchAndDecryptWorldOrSubPost(\n postHashHex: string,\n posterPubKeyHex: string,\n privDH: CryptoKey | undefined,\n worldKeyHex?: string,\n): Promise<{ post: TPost, encBuf: ArrayBuffer } | undefined> {\n const postHash = hex2bytes(postHashHex);\n if (!postHash) {\n return;\n }\n\n const encBuf = await Net.fetchPost(posterPubKeyHex, postHashHex);\n if (!encBuf) {\n return;\n }\n\n // TODO: use world key or sub key as appropriate--not both.\n if (worldKeyHex) {\n const worldPost = await fetchAndDecryptPost(\n posterPubKeyHex,\n worldKeyHex,\n encBuf,\n postHash,\n );\n if (worldPost) {\n return { post: worldPost, encBuf };\n }\n }\n\n if (privDH) {\n const subPost = await fetchAndDecryptPostWithSubKey(\n privDH,\n posterPubKeyHex,\n encBuf,\n postHash,\n );\n if (subPost) {\n return { post: subPost, encBuf };\n }\n }\n}\n\nexport async function publishPostAndKeys(\n post: TPost,\n worldKeyHex: string,\n privDH: CryptoKey,\n pubKey: string,\n privKey: CryptoKey,\n token: string,\n visibility: PostVisibility,\n) {\n const postKey = await Crypto.genSymmetricKey();\n\n const [newIndex, postHash] = await publishPost(\n post,\n postKey,\n pubKey,\n privKey,\n token,\n );\n\n const postHashHex = buf2hex(postHash)\n DB.posts.add({ post, hash: postHashHex, publisherPubKey: pubKey }, postHashHex);\n\n if (visibility === \"world\") {\n await publishPostWorldKey(\n worldKeyHex,\n postKey,\n postHash,\n pubKey,\n privKey,\n token,\n );\n } else if (visibility === \"subs\") {\n const subs = await getSubscriberPubKeyList();\n const subPubKeys = subs.map(sub => sub.pubKey);\n\n // Encrypt post for self, to allow refetching from host, without local post cache (e.g. after re-login).\n const targetPubKeys = subPubKeys.concat(pubKey);\n\n const promises = targetPubKeys.map((subPubKey) =>\n publishPostSubKey(\n privDH,\n subPubKey,\n postKey,\n postHash,\n pubKey,\n privKey,\n token,\n ),\n );\n await Promise.all(promises);\n }\n\n return newIndex;\n}\n\nexport async function publishPostWorldKey(\n worldKeyHex: string,\n postKey: CryptoKey,\n postHash: ArrayBuffer,\n pubKeyHex: string,\n privKey: CryptoKey,\n token: string,\n) {\n const worldKeyBytes = hex2bytes(worldKeyHex);\n if (!worldKeyBytes) {\n return;\n }\n const worldKey = await Crypto.importAESKey(worldKeyBytes, [\"encrypt\"]);\n\n // TODO: cleanup.\n const keyLoc = await postKeyLocation(worldKey, postHash);\n await DB.postKeys.put({\n postHash: buf2hex(postHash),\n subPubKey: worldKeyHex,\n keyLoc,\n });\n\n await publishPostKey(postKey, postHash, worldKey, pubKeyHex, privKey, token);\n}\n\nexport async function publishPostSubKey(\n privDH: CryptoKey,\n subPubKey: string,\n postKey: CryptoKey,\n postHash: ArrayBuffer,\n pubKey: string,\n privKey: CryptoKey,\n token: string,\n) {\n const subDHPub = await Crypto.hex2ECDHKey(subPubKey);\n if (!subDHPub) {\n return;\n }\n\n const encDH = await Crypto.deriveDHKey(subDHPub, privDH, [\"encrypt\", \"decrypt\"]);\n\n // TODO: cleanup.\n const keyLoc = await postKeyLocation(encDH, postHash);\n await DB.postKeys.put({\n postHash: buf2hex(postHash),\n subPubKey,\n keyLoc,\n });\n\n await publishPostKey(postKey, postHash, encDH, pubKey, privKey, token);\n}\n\nexport async function sendSubRequest(\n pubPubKeyHex: string,\n subPubKeyHex: string,\n msg: string,\n destHost: string,\n srcHost: string,\n): Promise {\n const message: ISubReq = {\n type: \"subscribe\",\n pubKey: subPubKeyHex,\n msg,\n host: srcHost,\n };\n\n return sendMessage(pubPubKeyHex, message, destHost);\n}\n\nexport async function publishPost(\n post: TPost,\n postKey: CryptoKey,\n pubKey: string,\n privKey: CryptoKey,\n token: string,\n): Promise<[IIndex, ArrayBuffer]> {\n const api = new API(Net, Crypto);\n return api.publishPost(post, postKey, pubKey, privKey, token);\n}\n\nexport async function postKeyLocation(\n outerKey: CryptoKey,\n postHash: ArrayBuffer,\n): Promise {\n const api = new API(Net, Crypto);\n return api.postKeyLocation(outerKey, postHash);\n}\n\nexport async function publishPostKey(\n postKey: CryptoKey,\n postHash: ArrayBuffer,\n encKey: CryptoKey,\n pubKey: string,\n privKey: CryptoKey,\n token: string,\n): Promise {\n const api = new API(Net, Crypto);\n return api.publishPostKey(postKey, postHash, encKey, pubKey, privKey, token);\n}\n\nexport async function putFile(\n pubKeyHex: string,\n path: string,\n signPrivKey: CryptoKey,\n token: string,\n data: ArrayBuffer,\n contentType: \"application/json\" | \"application/octet-stream\",\n): Promise {\n const api = new API(Net, Crypto);\n return api.putFile(pubKeyHex, path, signPrivKey, token, data, contentType);\n}\n\nexport async function getUserAuthChallenge(\n publicKey: CryptoKey,\n): Promise {\n const api = new API(Net, Crypto);\n return api.getUserAuthChallenge(publicKey);\n}\n\nexport async function getMessageAuthChallenge(\n message: ArrayBuffer,\n host?: string,\n): Promise {\n const hash = await Crypto.sha(message);\n const hashHex = buf2hex(hash);\n\n const capDesc = {\n type: \"message\",\n hash: hashHex,\n numBytes: message.byteLength,\n } as const;\n return Net.fetchAuthChallenge(capDesc, host);\n}\n\nexport async function getSessionToken(\n privateKey: CryptoKey,\n publicKey: CryptoKey,\n solution: Uint8Array,\n): Promise {\n const api = new API(Net, Crypto);\n return api.getSessionToken(privateKey, publicKey, solution);\n}\n","type EventListener = () => void;\n\nexport default class EventBus {\n listeners = new Set();\n\n on(l: EventListener) {\n this.listeners.add(l);\n }\n\n off (l: EventListener) {\n this.listeners.delete(l);\n }\n\n emit() {\n this.listeners.forEach(l => l());\n }\n}","import solvePoWChallenge from \"core/challenge\";\nimport { getUserAuthChallenge, getSessionToken } from \"lib/api\";\n\n\nexport async function getToken(pubKey: CryptoKey, privKey: CryptoKey, setStatus: (status: string) => void): Promise {\n setStatus(\"Initiating challenge...\");\n const { chal, diff } = await getUserAuthChallenge(pubKey);\n\n setStatus(\"Searching for solution...\");\n const solution = await solvePoWChallenge(chal, diff);\n if (!solution) {\n setStatus(\"No solution found.\");\n return new Error(\"No solution found\");\n }\n setStatus(\"Found solution.\");\n\n const token = await getSessionToken(\n privKey,\n pubKey,\n solution\n );\n setStatus(`Got access token.`);\n\n return token;\n}\n","// State models client state that should sync with the host via an E2E-encrypted file.\n// Excludes posts, because those already sync up to the host for distribution.\n\nimport Net from \"lib/net\";\nimport { hex2bytes } from \"core/bytes\";\nimport Crypto from \"lib/crypto\";\nimport { getPublicKeyHex } from \"lib/auth\";\nimport { dumpState, loadStateDangerously } from \"lib/db\";\nimport { putFile } from \"lib/api\";\nimport { getStateKey } from \"lib/storage\";\nimport { loadID } from \"models/id\";\n\nasync function putState(): Promise {\n const state = await dumpState();\n\n const ident = await loadID();\n if (!ident) {\n return;\n }\n\n const pubKeyHex = ident.pubKey.hex;\n\n const plaintext = JSON.stringify(state);\n\n const stateKeyHex = getStateKey();\n if (!stateKeyHex) {\n return;\n }\n const stateKeyBytes = hex2bytes(stateKeyHex);\n if (!stateKeyBytes) {\n return;\n }\n const stateKey = await Crypto.importAESKey(stateKeyBytes, [\"encrypt\"]);\n\n const ciphertext = await Crypto.encryptString(plaintext, stateKey);\n\n // Obscure filename?\n return putFile(pubKeyHex, \"state.json\", ident.privKey.key, ident.token, ciphertext, \"application/json\");\n}\n\nexport async function fetchState(): Promise {\n const pubKeyHex = await getPublicKeyHex();\n if (!pubKeyHex) {\n return;\n }\n\n const loc = Net.fileLoc(pubKeyHex, \"state.json\");\n const ciphertext = await Net.getFile(loc);\n if (!ciphertext) {\n return;\n }\n\n const stateKeyHex = getStateKey();\n if (!stateKeyHex) {\n return;\n }\n const stateKeyBytes = hex2bytes(stateKeyHex);\n if (!stateKeyBytes) {\n return;\n }\n const stateKey = await Crypto.importAESKey(stateKeyBytes, [\"decrypt\"]);\n\n const plaintext = await Crypto.decryptString(ciphertext, stateKey);\n\n // TODO: test this blows up if it fails to decrypt.\n\n const state = JSON.parse(plaintext);\n\n return loadStateDangerously(state);\n}\n\nexport async function mutateState(mutateFn: () => Promise) {\n // NOTE: race condition, here.\n // Use CRDTs to eliminate that?\n\n await fetchState();\n await mutateFn();\n await putState();\n}","import { getPrivateKey, getPublicKey, getPublicKeyHex } from \"lib/auth\";\nimport { wipeDB } from \"lib/db\";\nimport EventBus from \"lib/eventBus\";\nimport { getToken, getWorldKey, loadCreds, setIDKeys, setStateKey, setToken, setWorldKey } from \"lib/storage\";\nimport * as Host from \"models/host\";\nimport { useEffect, useState, createContext } from \"react\";\nimport { fetchAndStoreOwnProfile } from \"./profile\";\nimport { fetchState } from \"./state\";\n\nexport interface ID {\n pubKey: {\n key: CryptoKey,\n hex: string,\n },\n privKey: {\n key: CryptoKey,\n dhKey: CryptoKey,\n },\n token: string,\n worldKey: {\n hex: string,\n }\n}\n\nexport const IdentityContext = createContext(undefined);\n\nexport async function loadID(): Promise {\n const pubKey = await getPublicKey();\n const pubKeyHex = await getPublicKeyHex();\n const privKey = await getPrivateKey(\"ECDSA\");\n const privDH = await getPrivateKey(\"ECDH\");\n const token = getToken();\n const worldKeyHex = getWorldKey();\n\n if (!token || !pubKey || !pubKeyHex || !privKey || !privDH || !worldKeyHex) {\n return;\n }\n\n return {\n pubKey: {\n key: pubKey,\n hex: pubKeyHex,\n },\n privKey: {\n key: privKey,\n dhKey: privDH,\n },\n token,\n worldKey: {\n hex: worldKeyHex,\n },\n };\n}\n\nconst idChange = new EventBus();\n\n// undefined means loading; null means error\nexport function useID(): ID | undefined | null {\n const [id, setID] = useState();\n\n useEffect(() => {\n async function reloadID() {\n const id = await loadID();\n if (id) {\n setID(id);\n } else {\n setID(null);\n }\n }\n\n reloadID();\n\n idChange.on(reloadID);\n\n return () => {\n idChange.off(reloadID);\n }\n }, []);\n\n return id;\n}\n\nexport async function identify(creds: string, setStatus: (status: string) => void): Promise {\n setStatus(\"Loading creds...\");\n loadCreds(creds);\n setStatus(\"Loaded creds.\");\n\n await fetchState();\n \n // Fetch token.\n const pubKey = await getPublicKey();\n const privKey = await getPrivateKey(\"ECDSA\");\n if (!pubKey || !privKey) {\n return true;\n }\n const token = await Host.getToken(pubKey, privKey, setStatus);\n\n if (token instanceof Error) {\n setStatus(\"Failed to get token.\");\n return true;\n }\n setToken(token);\n \n await fetchAndStoreOwnProfile();\n\n idChange.emit();\n}\n\nexport async function deidentify() {\n localStorage.clear();\n idChange.emit();\n await wipeDB();\n}\n\nexport async function storeCredentials(idKeys: CryptoKeyPair, token: string, worldKey: CryptoKey, stateKey: CryptoKey) {\n setToken(token);\n await setIDKeys(idKeys);\n await setWorldKey(worldKey);\n await setStateKey(stateKey);\n idChange.emit();\n}\n","import { concatArrayBuffers } from \"core/bytes\";\nimport solvePoWChallenge from \"core/challenge\";\nimport { ecdsaParams, NUM_SIG_BYTES } from \"core/consts\";\nimport Crypto from \"lib/crypto\";\nimport { IMessage } from \"core/types\";\nimport { getMessageAuthChallenge } from \"lib/api\";\nimport Net from \"lib/net\";\nimport { loadID } from \"./id\";\n\nexport async function unwrapInboxItem(\n id: string,\n pubKeyHex: string,\n privKey: CryptoKey,\n): Promise {\n const ephemDHPub = await Crypto.hex2ECDHKey(id);\n if (!ephemDHPub) {\n return;\n }\n\n const ephemDH = await Crypto.deriveDHKey(ephemDHPub, privKey, [\"decrypt\"]);\n\n const enc = await Net.fetchInboxItem(pubKeyHex, id);\n if (!enc) {\n return;\n }\n const decBuf = await Crypto.decryptBuf(enc, ephemDH);\n const sig = decBuf.slice(0, NUM_SIG_BYTES);\n const rest = decBuf.slice(NUM_SIG_BYTES);\n\n const json = new TextDecoder().decode(rest);\n const msg = JSON.parse(json) as IMessage;\n\n const signerPubKeyHex = msg.pubKey;\n const signerPubKey = await Crypto.hex2ECDSAKey(signerPubKeyHex);\n if (!signerPubKey) {\n return; // TODO: signal error.\n }\n\n const valid = await crypto.subtle.verify(\n ecdsaParams,\n signerPubKey,\n sig,\n rest,\n );\n if (!valid) {\n return; // TODO blow up.\n }\n\n return msg;\n}\n\nexport async function sendMessage(\n destPubKeyHex: string,\n message: IMessage,\n host?: string,\n): Promise {\n const userPubKey = await Crypto.hex2ECDSAKey(destPubKeyHex);\n if (!userPubKey) {\n return;\n }\n\n const ident = await loadID();\n if (!ident) {\n // TODO: blow up. Switch all these to exceptions.\n return;\n } \n\n // Sign message.\n const msgJson = JSON.stringify(message);\n const msgBuf = new TextEncoder().encode(msgJson);\n const sig = await Crypto.sign(ident.privKey.key, msgBuf);\n const signed = concatArrayBuffers(sig, msgBuf);\n\n const pubECDH = await Crypto.pubECDSA2ECDH(userPubKey);\n\n // Gen ephem keypair for outer DH.\n const ephemKeys = await Crypto.genECDHKeys();\n const ephemDH = await Crypto.deriveDHKey(pubECDH, ephemKeys.privateKey, [\"encrypt\"]);\n\n // Encrypt request.\n const encReqBuf = await Crypto.encryptBuf(signed, ephemDH);\n\n // Get PoW challenge and solve it.\n const { chal, diff } = await getMessageAuthChallenge(encReqBuf, host);\n const solution = await solvePoWChallenge(chal, diff);\n if (!solution) {\n // TODO: signal failure.\n return;\n }\n\n const ephemDHPubBuf = await Crypto.key2buf(ephemKeys.publicKey);\n return Net.putMessage(destPubKeyHex, ephemDHPubBuf, encReqBuf, solution, host);\n}\n","import { buf2hex } from \"core/bytes\";\nimport Crypto from \"lib/crypto\";\nimport { IEncPost, IReply } from \"core/types\";\nimport DB from \"lib/db\";\nimport { recordReplyInDB } from \"lib/storage\";\nimport { useEffect, useState } from \"react\";\nimport { ID } from \"./id\";\nimport { sendMessage } from \"./message\";\n\nexport async function sendReply(\n postId: string,\n pubPubKeyHex: string,\n senderPubKeyHex: string,\n msg: string,\n host?: string,\n): Promise {\n const message: IReply = {\n type: \"reply\",\n pubKey: senderPubKeyHex,\n msg,\n postId,\n createdAt: new Date().toISOString(),\n };\n\n await sendMessage(pubPubKeyHex, message, host);\n await recordReplyInDB(message);\n\n return message;\n}\n\nexport async function replyId(reply: IReply): Promise {\n // TODO: compute hash to encompass full reply struct. Just hashing the msg field means every identical text message will collide.\n const buf = new TextEncoder().encode(reply.msg);\n const hash = await Crypto.sha(buf);\n const hashHex = await buf2hex(hash);\n return hashHex;\n}\n\nexport function useReplies(ident: ID | null | undefined): IEncPost[] | undefined {\n const [replies, setReplies] = useState();\n\n useEffect(() => {\n if (!ident) {\n return;\n }\n\n DB.posts.where({ publisherPubKey: ident.pubKey.hex })\n .and((post: any) => post.replyToHash != null)\n .toArray()\n .then((posts: any[]) => {\n const repls = posts.map((post: any) => {\n return { id: post.hash };\n });\n setReplies(repls);\n })\n .catch((err: any) => console.error(err));\n }, [ident]);\n\n return replies;\n}\n","import { useEffect, useState } from \"react\";\nimport { buf2hex } from \"core/bytes\";\nimport Crypto from \"lib/crypto\";\nimport DB from \"lib/db\";\nimport { IReply } from \"core/types\";\nimport { replyId } from \"models/reply\";\n\nconst tokenKey = \"token\";\nconst privKeyKey = \"privKey\";\nconst pubKeyKey = \"pubKey\";\nconst worldKeyKey = \"worldKey\";\nconst stateKeyKey = \"stateKey\";\n\nexport function setToken(token: string) {\n localStorage[tokenKey] = token;\n}\n\nexport async function setIDKeys(idKeys: CryptoKeyPair) {\n const pubJWK = await crypto.subtle.exportKey(\"jwk\", idKeys.publicKey);\n\n // const pubBuf = await crypto.subtle.exportKey(\"spki\", idKeys.publicKey);\n // const pubStr = new TextDecoder().decode(new Uint8Array(pubBuf));\n // debugger;\n // const pubB64 = btoa(pubStr);\n // console.log(\"pub\", pubStr, pubB64);\n\n // const privBuf = await crypto.subtle.exportKey(\"pkcs8\", idKeys.privateKey);\n // const privStr = new TextDecoder().decode(privBuf);\n // const privB64 = btoa(privStr);\n // console.log(\"priv\", privStr, privB64);\n \n const privJWK = await crypto.subtle.exportKey(\"jwk\", idKeys.privateKey);\n localStorage[pubKeyKey] = JSON.stringify(pubJWK);\n localStorage[privKeyKey] = JSON.stringify(privJWK);\n}\n\nexport async function setWorldKey(key: CryptoKey) {\n const buf = await Crypto.key2buf(key);\n const hex = buf2hex(buf);\n localStorage[worldKeyKey] = hex;\n}\n\nexport async function setStateKey(key: CryptoKey) {\n const buf = await Crypto.key2buf(key);\n const hex = buf2hex(buf);\n localStorage[stateKeyKey] = hex;\n}\n\nexport function getToken(): string | undefined {\n return localStorage[tokenKey];\n}\n\nexport function getPrivateKeyJWK(): string | undefined {\n return localStorage[privKeyKey];\n}\n\nexport function getPublicKeyJWK(): string | undefined {\n return localStorage[pubKeyKey];\n}\n\nexport function getWorldKey(): string | undefined {\n return localStorage[worldKeyKey];\n}\n\nexport function getStateKey(): string | undefined {\n return localStorage[stateKeyKey];\n}\n\nexport async function getSubscriberPubKeyList(): Promise<{ pubKey: string }[]> {\n return DB.followers.toArray();\n}\n\nexport async function addSubscriptionPubKey(pubKey: string, host: string, worldKeyHex: string, handle?: string) {\n return DB.subscriptions.add({ pubKey, host, worldKeyHex, handle })\n .catch(() => {});\n}\n\nexport function useSubscribers(): [any[] | undefined, () => void] {\n const [subs, setSubs] = useState();\n\n function fetchSubs() {\n DB.profiles.filter((p: any) => p.followsMe).toArray()\n .then((subs: any[]) => { setSubs(subs) })\n .catch((err: any) => {\n console.error(err);\n });\n }\n\n useEffect(() => {\n fetchSubs(); \n }, []);\n\n return [subs, fetchSubs];\n}\n\nexport function dumpState(): string | undefined {\n const { pubKey, privKey, worldKey, stateKey } = localStorage;\n try {\n const json = JSON.stringify(\n {\n pubKey: JSON.parse(pubKey),\n privKey: JSON.parse(privKey),\n worldKey,\n stateKey,\n }, null, 2\n );\n return json;\n } catch (e) {\n return undefined;\n }\n}\n\nexport function loadCreds(stateJSON: string) {\n try {\n const state = JSON.parse(stateJSON);\n const { pubKey, privKey, worldKey, stateKey } = state;\n localStorage[pubKeyKey] = JSON.stringify(pubKey);\n localStorage[privKeyKey] = JSON.stringify(privKey);\n localStorage[worldKeyKey] = worldKey;\n localStorage[stateKeyKey] = stateKey;\n } catch {\n }\n}\n\nexport async function recordReplyInDB(reply: IReply) {\n const hashHex = await replyId(reply);\n return DB.posts.put({\n hash: hashHex,\n replyToHash: reply.postId,\n publisherPubKey: reply.pubKey,\n post: {\n content: {\n text: reply.msg,\n },\n createdAt: reply.createdAt,\n type: \"text\",\n },\n });\n}\n","import { bytes2hex } from \"../bytes\";\n\nexport async function json2hex(json: string, crypto: Crypto): Promise {\n const key = await json2key(json, \"ECDSA\", [], crypto);\n if (!key) {\n return;\n }\n\n try {\n const raw = await crypto.subtle.exportKey(\"raw\", key);\n const bytes = new Uint8Array(raw);\n return bytes2hex(bytes);\n } catch (e) {\n return undefined;\n }\n}\n\nexport async function json2key(json: string, keyType: \"ECDSA\" | \"ECDH\", usages: KeyUsage[], crypto: Crypto): Promise {\n let jwk;\n try {\n jwk = JSON.parse(json);\n } catch {\n return undefined;\n }\n\n try {\n if (keyType === \"ECDH\") {\n jwk.key_ops = [\"deriveKey\"];\n }\n const key = await crypto.subtle.importKey(\n \"jwk\",\n jwk,\n { name: keyType, namedCurve: \"P-256\" },\n true,\n usages,\n );\n return key;\n } catch (e) {\n console.log(e);\n return undefined;\n }\n}","import { getPrivateKeyJWK, getPublicKeyJWK } from \"lib/storage\";\nimport { json2hex, json2key } from \"core/client/lib\";\n\nexport function isAuthenticated(): boolean {\n return getPublicKeyJWK() != null;\n}\n\nexport async function getPublicKeyHex(): Promise {\n const json = getPublicKeyJWK();\n if (!json) {\n return;\n }\n\n return json2hex(json, crypto);\n}\n\nexport async function getPublicKey(): Promise {\n const json = getPublicKeyJWK();\n if (!json) {\n return;\n }\n return json2key(json, \"ECDSA\", [], crypto);\n}\n\nexport async function getPrivateKey(keyType: \"ECDSA\" | \"ECDH\"): Promise {\n const json = getPrivateKeyJWK();\n if (!json) {\n return;\n }\n const usage = keyType === \"ECDSA\" ? \"sign\" : \"deriveKey\";\n return json2key(json, keyType, [usage], crypto);\n}\n","import { hex2bytes } from \"../bytes\";\n\nexport interface ICreds {\n idKeys: CryptoKeyPair;\n stateKey: CryptoKey;\n worldKey: CryptoKey;\n}\n\nexport async function loadFromJSON(json: string, crypto: Crypto): Promise {\n try {\n const id = JSON.parse(json);\n\n const publicKey = await crypto.subtle.importKey(\"jwk\", id.pubKey, { name: \"ECDSA\", namedCurve: \"P-256\" }, true, [\"verify\"]);\n const privateKey = await crypto.subtle.importKey(\"jwk\", id.privKey, { name: \"ECDSA\", namedCurve: \"P-256\" }, true, [\"sign\"]);\n\n const idKeys = { publicKey, privateKey };\n\n const worldKeyBufResult = hex2bytes(id.worldKey);\n if (worldKeyBufResult == null) {\n return new Error(\"Parsing world key\");\n }\n const worldKey = await crypto.subtle.importKey(\"raw\", worldKeyBufResult, { name: \"AES-CBC\", length: 256 }, true, [\"encrypt\", \"decrypt\"]);\n\n const stateKeyBufResult = hex2bytes(id.stateKey);\n if (stateKeyBufResult == null) {\n return new Error(\"Parsing state key\");\n }\n const stateKey = await crypto.subtle.importKey(\"raw\", stateKeyBufResult, { name: \"AES-CBC\", length: 256 }, false, [\"encrypt\", \"decrypt\"]);\n\n return { idKeys, stateKey, worldKey };\n } catch (e) {\n console.error(e)\n return new Error(\"dunno\");\n }\n}","import { buf2hex, bytes2hex } from \"core/bytes\";\nimport Crypto from \"lib/crypto\";\nimport { IProfile } from \"core/types\";\nimport { hostPrefix } from \"lib/net\";\nimport { getToken } from \"./host\";\nimport { storeCredentials } from \"./id\";\nimport { storeProfile, uploadProfile } from \"./profile\";\nimport { loadFromJSON } from \"core/client/creds\";\n\nexport class AuthorizedUser {\n user: User;\n token: string;\n\n constructor(user: User, token: string) {\n this.user = user;\n this.token = token;\n }\n\n async storeCreds() {\n return storeCredentials(this.user.idKeys, this.token, this.user.worldKey, this.user.stateKey);\n }\n\n async storeAndUploadProfile(): Promise {\n const profile = await this.user.profile();\n const pubKeyResult = await this.user.pubKeyHex();\n\n if (pubKeyResult instanceof Error) {\n return pubKeyResult;\n }\n\n await Promise.all([\n storeProfile(pubKeyResult, profile),\n uploadProfile(this.user.idKeys.publicKey, this.user.idKeys.privateKey, this.token, profile),\n ]);\n }\n}\n\nexport default class User {\n idKeys: CryptoKeyPair;\n stateKey: CryptoKey;\n worldKey: CryptoKey;\n\n constructor(idKeys: CryptoKeyPair, stateKey: CryptoKey, worldKey: CryptoKey) {\n this.idKeys = idKeys;\n this.stateKey = stateKey;\n this.worldKey = worldKey;\n }\n\n static async create(): Promise {\n const idKeys = await Crypto.genIDKeyPair();\n const stateKey = await Crypto.genSymmetricKey();\n const worldKey = await Crypto.genSymmetricKey();\n\n return new User(idKeys, stateKey, worldKey);\n }\n\n static async loadFromJSON(json: string): Promise {\n const creds = await loadFromJSON(json, crypto);\n if (creds instanceof Error) {\n return creds;\n }\n\n return new User(creds.idKeys, creds.stateKey, creds.worldKey);\n }\n\n async getToken(setStatus: (status: string) => void): Promise {\n const token = await getToken(this.idKeys.publicKey, this.idKeys.privateKey, setStatus);\n if (token instanceof Error) {\n return token;\n }\n\n return new AuthorizedUser(this, token);\n }\n\n async profile(): Promise {\n const worldKeyBuf = await Crypto.key2buf(this.worldKey);\n const worldKeyHex = buf2hex(worldKeyBuf);\n return { worldKey: worldKeyHex, host: hostPrefix };\n }\n\n async pubKeyHex(): Promise {\n try {\n const raw = await crypto.subtle.exportKey(\"raw\", this.idKeys.publicKey);\n const bytes = new Uint8Array(raw);\n return bytes2hex(bytes);\n } catch (e) {\n return e;\n }\n }\n}","import { buf2hex, concatArrayBuffers } from \"core/bytes\";\nimport Crypto from \"lib/crypto\";\nimport { IIndex, IProfile, ISubReq, NotFound } from \"core/types\";\nimport { getPublicKeyHex } from \"lib/auth\";\nimport DB from \"lib/db\";\nimport Net from \"lib/net\";\nimport { useState, useEffect } from \"react\";\nimport { loadID } from \"./id\";\nimport { putFile } from \"lib/api\";\nimport { mutateState } from \"./state\";\nimport User from \"./user\";\n\n// TODO: standardize userId vs. pubKeyHex.\nexport function fetchProfile(userId: string, host?: string): Promise {\n const location = Net.fileLoc(userId, \"profile.json\");\n return Net.getFileSignedJSON(userId, location, host);\n}\n\nexport function useIndex(id: string, host?: string): IIndex | \"notfound\" {\n const [index, setIndex] = useState({ posts: [], updatedAt: \"\" });\n useEffect(() => {\n // TODO: manage potential local/remote index conflicts (CRDT). Currently it is most-recent wins.\n async function load() {\n let updatedAt = \"\";\n\n const row = await DB.indexes.get(id);\n if (row) {\n setIndex(row.index);\n updatedAt = row.index.updatedAt;\n }\n\n const location = Net.fileLoc(id, \"index.json\");\n const remoteIndex = await Net.getFileSignedJSON(id, location, host);\n if (remoteIndex && remoteIndex !== \"notfound\" && remoteIndex.updatedAt > updatedAt) {\n setIndex(remoteIndex);\n }\n }\n\n if (!id) {\n return;\n }\n\n load();\n }, [id, host]);\n\n return index;\n}\n\nasync function loadProfile(userId: string): Promise {\n return DB.profiles.get(userId);\n}\n\nexport function useProfile(userId?: string, host?: string): [IProfile | NotFound, (newProfile: IProfile) => void] {\n const defaultProfile: IProfile = { worldKey: \"\" };\n const [profile, setProfile] = useState(defaultProfile);\n\n useEffect(() => {\n if (!userId) {\n return;\n }\n\n async function get(userId: string, host?: string): Promise {\n const local = await loadProfile(userId);\n if (local) {\n return local;\n }\n\n const remote = await fetchProfile(userId, host);\n return remote;\n }\n\n get(userId, host)\n .then((p) => {\n if (p) {\n setProfile(p);\n }\n });\n }, [userId, host]);\n\n async function updateProfile(newProfile: IProfile): Promise {\n if (!userId) {\n return;\n }\n\n setProfile(newProfile);\n\n await storeProfile(userId, newProfile);\n console.log(newProfile);\n\n const ident = await loadID();\n if (!ident) {\n return;\n }\n\n return uploadProfile(ident.pubKey.key, ident.privKey.key, ident.token, newProfile);\n }\n\n return [profile, updateProfile];\n}\n\nexport async function storeProfile(pubKeyHex: string, profile: IProfile, following: boolean = false, followsMe: boolean = false) {\n return DB.profiles.put({\n pubKey: pubKeyHex,\n host: profile.host,\n worldKey: profile.worldKey, // TODO: standardize all these Hex suffixes.\n handle: profile.handle,\n bio: profile.bio,\n following,\n followsMe,\n })\n}\n\nexport async function fetchAndStoreOwnProfile() {\n const pubKeyHex = await getPublicKeyHex();\n if (pubKeyHex) {\n const profile = await fetchProfile(pubKeyHex);\n if (profile && profile !== \"notfound\") {\n storeProfile(pubKeyHex, profile);\n }\n }\n}\n\nexport async function uploadProfile(pubKey: CryptoKey, privKey: CryptoKey, token: string, profile: IProfile) {\n const pubKeyBuf = await Crypto.key2buf(pubKey);\n const pubKeyHex = buf2hex(pubKeyBuf);\n\n const payload = new TextEncoder().encode(JSON.stringify(profile));\n const sig = await Crypto.sign(privKey, payload);\n const signed = concatArrayBuffers(sig, payload);\n\n return putFile(pubKeyHex, \"profile.json\", privKey, token, signed, \"application/json\");\n}\n\nexport async function createProfile(setStatus: (status: string) => void) {\n const user = await User.create()\n const authedUser = await user.getToken(setStatus);\n if (authedUser instanceof Error) {\n return; // TODO: handle these intermediate errors.\n }\n\n await authedUser.storeCreds();\n\n await authedUser.storeAndUploadProfile();\n}\n\nexport function useIsSubscribedTo(pubKeyHex: string): boolean {\n const [isSubscribed, setIsSubscribed] = useState(false);\n useEffect(() => {\n if (!pubKeyHex) {\n return;\n }\n\n DB.subscriptions.get(pubKeyHex).then((sub: any) => {\n setIsSubscribed(sub != null);\n });\n }, [pubKeyHex])\n\n return isSubscribed;\n}\n\nexport async function follow(pubKeyHex: string, profile: IProfile) {\n return DB.profiles.put({\n pubKey: pubKeyHex,\n host: profile.host,\n worldKey: profile.worldKey, // TODO: standardize all these Hex suffixes.\n handle: profile.handle,\n bio: profile.handle,\n following: true,\n followsMe: false, // TODO: handle case of overwrite. Maybe using separate table to track follower/following.\n });\n}\n\nexport async function acceptFollower(pubKeyHex: string, profile: IProfile) {\n return DB.profiles.put({\n pubKey: pubKeyHex,\n host: profile.host,\n worldKey: profile.worldKey, // TODO: standardize all these Hex suffixes.\n handle: profile.handle,\n bio: profile.handle,\n following: false, // TODO: handle case of overwrite. Maybe using separate table to track follower/following.\n followsMe: true,\n });\n}\n\nexport async function addSubscriber(req: ISubReq) {\n const profile = await fetchProfile(req.pubKey, req.host);\n\n if (!profile || profile === \"notfound\") {\n return; // TODO: handle error.\n }\n\n return mutateState(async () => {\n await acceptFollower(req.pubKey, profile);\n return DB.followers.put({\n pubKey: req.pubKey,\n host: req.host,\n });\n });\n}\n","import { createProfile } from \"models/profile\";\nimport { useState } from \"react\";\nimport { Link, useLocation, useNavigate } from \"react-router-dom\";\n\nexport default function Access() {\n const [status, setStatus] = useState(\"\");\n const navigate = useNavigate();\n const location = useLocation();\n\n const next = location.search;\n\n async function handleCreateIDClicked() {\n await createProfile(setStatus);\n navigate(`/creds/dump${next}`)\n }\n\n function handleLoadIDClicked() {\n navigate(`/creds/load${next}`)\n }\n\n return (\n
\n
\n \"Pixelated\n

neopub

\n
\n
\n

Neopub is an end-to-end encrypted, open-source, self-hosted social network.

\n

In neopub, you don't have an email and password. Your identity is cryptographic.

\n \n \n {status}\n
\n
\n );\n}\n","const colors: Record = {\n \"0\": \"#FECACA\",\n \"1\": \"#FDE68A\",\n \"2\": \"#A7F3D0\",\n \"3\": \"#BFDBFE\",\n \"4\": \"#C7D2FE\",\n \"5\": \"#DDD6FE\",\n \"6\": \"#FBCFE8\",\n \"7\": \"#F87171\",\n \"8\": \"#FBBF24\",\n \"9\": \"#34D399\",\n \"A\": \"#60A5FA\",\n \"B\": \"#818CF8\",\n \"C\": \"#A78BFA\",\n \"D\": \"#F472B6\",\n \"E\": \"#E5E7EB\",\n \"F\": \"#9CA3AF\",\n}\n\nexport default function Hexatar({ hex }: { hex: string }) {\n const dim = 3;\n\n const rows: string[][] = new Array(dim);\n for (let r = 0; r < dim; r++) {\n const start = r * dim;\n const cols = new Array(dim);\n for (let c = 0; c < dim; c++) {\n cols[c] = hex[start + c];\n }\n rows[r] = cols;\n }\n\n const lastChar = hex[hex.length - 1];\n const borderColor = colors[lastChar];\n\n return (\n
\n
\n {rows.map((row, r) => {\n return (\n
\n {\n row.map((char, c) => {\n const color = colors[char];\n return {char};\n })\n }\n
\n )\n })}\n
\n
\n )\n}","import QRCode from \"react-qr-code\";\n\nexport default function HexQR({ hex }: { hex: string }) {\n const QR = QRCode as any;\n\n const bgColor = \"#141623\";\n const fgColor = \"#2BAA18\";\n\n return (\n
\n \n
\n );\n}","export default function Timestamp({ ts }: { ts: string }) {\n const date = new Date(ts);\n const now = new Date();\n\n const isToday = date.toLocaleDateString() === now.toLocaleDateString();\n const isThisYear = date.getFullYear() === now.getFullYear();\n\n const dateOpts = {\n year: isThisYear ? undefined : \"numeric\",\n month: \"short\",\n day: \"numeric\",\n } as const;\n\n const timeOpts = {\n hour: \"numeric\",\n minute: \"numeric\",\n second: undefined,\n } as const;\n\n const fmt = new Intl.DateTimeFormat([], isToday ? timeOpts : dateOpts)\n\n const str = fmt.format(date);\n\n return
{str}
;\n}\n","import { ITextPost } from \"core/types\";\n\nexport default function TextPost({ post }: { post: ITextPost }) {\n return
{post.content.text}
;\n}\n","import { ICodePost } from \"core/types\";\n\nexport default function CodePost({ post }: { post: ICodePost }) {\n return
{post.content.code}
;\n}\n","import { TPost } from \"core/types\";\nimport TextPost from \"components/textPost\";\nimport CodePost from \"components/codePost\";\n\nexport default function PostContent({ post }: { post: TPost }) {\n switch (post.type) {\n case \"text\":\n return ;\n case \"code\":\n return ;\n }\n}\n","import { TPost } from \"core/types\";\nimport Timestamp from \"components/timestamp\";\nimport PostContent from \"components/postContent\";\nimport Hexatar from \"./hexatar\";\nimport { Link } from \"react-router-dom\";\n\nfunction Contents({post}: {post?: TPost}) {\n if (!post) {\n return
encrypted
;\n }\n\n return (\n
\n \n \n
\n )\n}\n\nexport default function Post({ id, post, pubKey }: { id: string, post?: TPost, pubKey: string }) {\n return (\n \n \n \n \n );\n}\n","import { hex2bytes } from \"core/bytes\";\nimport Crypto from \"lib/crypto\";\nimport { IEncPost, IIndex, ITextPost, PostVisibility, TPost } from \"core/types\";\nimport { fetchAndDecryptWorldOrSubPost, postKeyLocation, publishPostAndKeys } from \"lib/api\";\nimport DB from \"lib/db\";\nimport Net from \"lib/net\";\nimport { useEffect, useState } from \"react\";\nimport { ID, loadID } from \"./id\";\n\nexport type DBPost = any; // TODO.\n\nexport async function loadPosts(): Promise {\n return DB.posts.orderBy(\"createdAt\").reverse().toArray();\n}\n\nasync function fetchAndCachePost(pubKey: string, postHashHex: string, worldKeyHex: string, privDH: CryptoKey) {\n const res = await fetchAndDecryptWorldOrSubPost(\n postHashHex,\n pubKey,\n privDH,\n worldKeyHex,\n );\n if (!res) {\n return;\n } \n const { post } = res;\n\n return DB.posts.put({\n post,\n hash: postHashHex,\n publisherPubKey: pubKey,\n });\n}\n\nexport async function fetchPosts(privDH: CryptoKey) {\n const subs: { pubKey: string, host: string, worldKeyHex: string }[] = await DB.subscriptions.orderBy(\"pubKey\").toArray();\n\n await Promise.all(subs.map(async (sub) => {\n const { pubKey, host, worldKeyHex } = sub;\n const index = await Net.getIndex(pubKey, host);\n if (index === \"notfound\" || !index) {\n return;\n }\n\n return Promise.all(index.posts.map(async (post) => {\n const postHash = (post as IEncPost).id;\n \n const local = await DB.posts.get(postHash);\n if (local) {\n return;\n }\n\n return fetchAndCachePost(pubKey, postHash, worldKeyHex, privDH);\n }));\n }));\n};\n\nexport async function publishTextPost(id: ID, text: string, visibility: PostVisibility): Promise {\n const now = new Date();\n const post: ITextPost = {\n createdAt: now.toISOString(),\n type: \"text\",\n content: {\n text,\n },\n };\n \n const newIndex = await publishPostAndKeys(\n post,\n id.worldKey.hex,\n id.privKey.dhKey,\n id.pubKey.hex,\n id.privKey.key,\n id.token,\n visibility,\n );\n\n await DB.indexes.put({ pubKey: id.pubKey.hex, index: newIndex });\n\n return newIndex;\n}\n\nexport async function fetchAndDec(ident: ID, enc: IEncPost, pubKey: string, worldKeyHex?: string): Promise {\n const { id: postHashHex } = enc;\n\n const postRow = await DB.posts.get(postHashHex);\n if (postRow) {\n return postRow.post;\n }\n\n const res = await fetchAndDecryptWorldOrSubPost(\n postHashHex,\n pubKey,\n ident?.privKey.dhKey,\n worldKeyHex,\n );\n if (!res) {\n return;\n } \n const { post } = res;\n // setEncBuf(encBuf);\n\n async function cachePost() {\n return DB.posts.put({\n post,\n hash: postHashHex,\n publisherPubKey: pubKey,\n });\n }\n\n try {\n const isOwnPost = pubKey === ident?.pubKey.hex;\n if (isOwnPost) {\n await cachePost();\n } else {\n // Cache post if subscribed to poster.\n const sub = await DB.subscriptions.get(pubKey);\n if (sub) {\n await cachePost();\n }\n }\n } catch (err) {\n console.log(err, postHashHex)\n }\n\n return post;\n}\n\nexport function useAudience(postHash: string): string[] {\n const [pubKeys, setPubKeys] = useState([]);\n\n useEffect(() => {\n DB.postKeys.where({ postHash }).toArray()\n .then((postKeys: any[]) => {\n const pubKeys = postKeys.map(({ subPubKey }) => subPubKey);\n setPubKeys(pubKeys);\n });\n }, [postHash]);\n\n return pubKeys;\n}\n\nexport async function removeAccess(postHash: string, viewerPubKey: string) {\n const ident = await loadID();\n if (!ident) {\n // TODO: show error. Real TODO: rearchitect so ident must be present before calling this.\n return;\n }\n\n // TODO: manage the prefixing with pubkeyhex all on the server side. Client doesn't need to care about that.\n // const location = fileLoc(ident.pubKey.hex, `inbox/${id}`);\n // try {\n // deleteFile(ident.pubKey.hex, ident.token, location);\n // inboxChange.emit();\n // } catch (err) {\n // // TODO: handle in UI code.\n // alert(\"Failed to delete.\");\n // }\n\n const subDHPub = await Crypto.hex2ECDHKey(viewerPubKey);\n if (!subDHPub) {\n return;\n }\n\n const hashBuf = hex2bytes(postHash);\n if (!hashBuf) {\n return; // TODO.\n }\n\n const encDH = await Crypto.deriveDHKey(subDHPub, ident.privKey.dhKey, [\"encrypt\", \"decrypt\"]);\n\n const keyLoc = await postKeyLocation(encDH, hashBuf);\n\n const location = Net.fileLoc(ident.pubKey.hex, `keys/${keyLoc}`);\n try {\n await Net.deleteFile(ident.pubKey.hex, ident.token, location);\n } catch (err) {\n // TODO: handle in UI code.\n alert(\"Failed to delete from host.\");\n }\n\n await DB.postKeys.delete(keyLoc);\n}\n\nexport async function deletePost(postHash: string) {\n const ident = await loadID();\n if (!ident) {\n // TODO: show error. Real TODO: rearchitect so ident must be present before calling this.\n return;\n }\n\n const location = Net.fileLoc(ident.pubKey.hex, `posts/${postHash}`);\n try {\n await Net.deleteFile(ident.pubKey.hex, ident.token, location);\n } catch (err) {\n // TODO: handle in UI code.\n alert(\"Failed to delete from host.\");\n }\n\n await DB.posts.delete(postHash);\n\n // TODO: update index.\n\n // TODO: delete post keys too.\n}","import { TPost, IEncPost } from \"core/types\";\nimport { useContext, useEffect, useState } from \"react\";\nimport Post from \"components/post\";\nimport { IdentityContext } from \"models/id\";\nimport { fetchAndDec } from \"models/post\";\n\nexport default function EncryptedPost({\n enc,\n pubKey,\n worldKeyHex,\n}: {\n enc: IEncPost;\n pubKey: string;\n worldKeyHex?: string;\n}) {\n const ident = useContext(IdentityContext);\n\n const [post, setPost] = useState();\n useEffect(() => {\n if (!ident) {\n return;\n }\n\n fetchAndDec(ident, enc, pubKey, worldKeyHex)\n .then(post => setPost(post));\n }, [enc, pubKey, worldKeyHex, ident]);\n\n return ;\n}\n","import { IEncPost, IReply } from \"core/types\";\nimport { replyId, sendReply } from \"models/reply\";\nimport { useEffect } from \"react\";\nimport { useState } from \"react\";\nimport { Link, useLocation, useNavigate } from \"react-router-dom\";\n\nfunction ViewReplyButton({ reply }: { reply: IReply }) {\n const [id, setId] = useState();\n useEffect(() => {\n replyId(reply).then((hex) => {\n setId(hex);\n });\n }, [reply]);\n\n if (!id) {\n return null;\n }\n\n return View reply;\n}\n\nexport default function ReplyButton({ post, pubKeyHex, id, host }: { post: IEncPost; id: string; worldKeyHex?: string; pubKeyHex?: string; host: string; }) {\n const navigate = useNavigate();\n const location = useLocation();\n const [replyState, setReplyState] = useState<\"sending\" | \"sent\">();\n const [sentReply, setSentReply] = useState();\n\n async function handleReply(postId: string) {\n if (!pubKeyHex) {\n alert('You need an identity first.');\n navigate(`/?next=${encodeURIComponent(location.pathname)}`);\n return;\n }\n\n const reply = prompt(\"Reply\");\n if (!reply) {\n return;\n }\n\n try {\n setReplyState(\"sending\");\n\n const replyMsg = await sendReply(postId, id, pubKeyHex, reply, host);\n \n setReplyState(\"sent\");\n setSentReply(replyMsg);\n } catch (err) {\n alert(\"Failed to send reply.\");\n setReplyState(undefined);\n }\n }\n\n let text = \"Reply\";\n if (replyState === \"sending\") {\n text = \"Sending...\";\n } else if (replyState === \"sent\") {\n text = \"Reply sent.\";\n }\n\n return (\n \n );\n}\n","import { IEncPost, TPost } from \"core/types\";\nimport EncryptedPost from \"./encryptedPost\";\nimport ReplyButton from \"./replyButton\";\n\nexport default function PostList({ pubKeyHex, posts, id, worldKeyHex, host, empty }: { posts: (TPost | IEncPost)[], id: string, worldKeyHex?: string, pubKeyHex?: string, host: string, empty: React.ReactElement }) {\n if (posts.length === 0) {\n return empty;\n }\n\n const showReply = id !== pubKeyHex;\n\n return (\n
\n {\n posts.map(\n (p, i) =>\n id && (\n
\n \n {showReply && }\n \n
\n ),\n )\n }\n
\n );\n}\n","export default function Empty({ text, subtext }: { text: string, subtext?: string }) {\n return (\n
\n
\n

{text}

\n {subtext &&
{subtext}
}\n
\n
\n );\n}","import { hostPrefix } from \"lib/net\";\nimport { Link } from \"react-router-dom\";\nimport Hexatar from \"./hexatar\";\n\nfunction MissingHandle() {\n return No handle;\n}\n\nexport default function HexIDCard({ pubKey, host, handle }: { pubKey: string, host?: string, handle?: string }) {\n let link = `/users/${pubKey}`;\n if (host && host !== hostPrefix) {\n link += `?host=${escape(host)}`;\n }\n\n return (\n \n \n {
{handle ? handle : }
}\n \n )\n}","import { useSubscribers } from \"lib/storage\";\nimport Empty from \"./empty\";\nimport HexIDCard from \"./hexIdCard\";\n\nfunction SubscriberItem({ profile }: { profile: any }) {\n const { pubKey, handle, host } = profile;\n return ;\n}\n\nexport default function SubscriberList() {\n const [subs] = useSubscribers();\n\n if (subs === undefined) {\n return null;\n }\n\n if (Object.values(subs).length < 1) {\n return \n }\n\n return (\n
\n {subs.map((sub) => )}\n
\n )\n}","import { sendSubRequest } from \"lib/api\";\nimport Net, { hostPrefix } from \"lib/net\";\nimport { mutateState } from \"models/state\";\nimport { addSubscriptionPubKey } from \"lib/storage\";\nimport { useState } from \"react\";\nimport { follow } from \"models/profile\";\n\nexport default function SubscribeView({ pubKeyHex }: { pubKeyHex: string }) {\n const [url, setURL] = useState(\"\");\n \n const re = new RegExp('(https:\\\\/\\\\/|http:\\\\/\\\\/)?([a-zA-Z\\\\./]+(:\\\\d+)?)\\\\/users\\\\/(\\\\w+?)\\\\?host=(.+)', 'i');\n const match = re.exec(url);\n\n async function handleSubscribe(evt: any) {\n evt.preventDefault();\n evt.stopPropagation();\n\n if (!url || !match) {\n return;\n }\n\n const pubPubKeyHex = match[4];\n if (pubPubKeyHex === pubKeyHex) {\n alert(\"You can't subscribe to yourself.\");\n return;\n }\n\n const destHost = unescape(match[5]);\n if (!destHost) {\n alert(\"Host not specified.\");\n return;\n }\n\n const msg = prompt(\"Enter a message to include with the request (optional).\")\n if (msg == null) {\n return;\n }\n\n const profile = await Net.getProfile(pubPubKeyHex, destHost);\n if (!profile || profile === \"notfound\") {\n return;\n }\n\n const worldKeyHex = profile.worldKey;\n const srcHost = hostPrefix;\n \n await sendSubRequest(pubPubKeyHex, pubKeyHex, msg, destHost, srcHost);\n\n await mutateState(async () => {\n await follow(pubPubKeyHex, profile);\n return addSubscriptionPubKey(pubPubKeyHex, destHost, worldKeyHex, profile.handle);\n });\n }\n\n return (\n
\n To follow someone from a different host, copy the QR code link from their profile and paste it here.\n
\n setURL(e.target.value)} className=\"py-1 px-3 rounded\" placeholder=\"Paste profile link here\" />\n \n
\n
\n )\n}\n","import DB from \"lib/db\";\nimport { useEffect } from \"react\";\nimport { useState } from \"react\";\nimport Empty from \"./empty\";\nimport HexIDCard from \"./hexIdCard\";\n\nfunction SubscriptionItem({ profile }: { profile: any }) {\n const { pubKey, handle, host } = profile;\n return ;\n}\n\nexport default function SubscriptionList() {\n const [subs, setSubs] = useState<{ pubKey: string, handle?: string, host: string}[]>([]);\n useEffect(() => {\n // NOTE: must use filter because IndexedDB doesn't support indexing boolean fields.\n DB.profiles.filter((p: any) => p.following).toArray()\n .then((profiles: any[]) => setSubs(profiles));\n }, [])\n\n if (subs === undefined) {\n return null;\n }\n\n if (subs.length < 1) {\n return \n }\n\n return (\n
\n {subs.map((profile: any) => )}\n
\n )\n}","import { useState } from \"react\";\n\n\nexport function TabBar({ tabs, activeTab, onTabSelected }: { tabs: string[], activeTab: string, onTabSelected: (tab: string) => void }) {\n return (\n
\n {\n tabs.map((tab) => {\n const isActive = tab === activeTab;\n return

onTabSelected(tab)} style={{ textUnderlineOffset: 2 }}>{tab}

\n })\n }\n
\n )\n}\n\nexport interface ITab {\n name: string;\n el: React.ReactElement;\n}\n\nexport default function Tabs({ tabs, initialActiveTab }: { tabs: ITab[], initialActiveTab: string }) {\n const [activeTab, setActiveTab] = useState(initialActiveTab);\n\n const activeEl = tabs.filter(tab => tab.name === activeTab)?.[0]?.el;\n return (\n <>\n t.name)} activeTab={activeTab} onTabSelected={(t) => setActiveTab(t)} />\n {activeEl}\n \n )\n}","import { useState } from \"react\";\n\nexport default function KnowMore({ more, label }: { more: React.ReactElement, label?: string }) {\n const [showMore, setShowMore] = useState(false);\n \n return (\n
\n \n { showMore && more }\n
\n )\n}","import { hostPrefix } from \"lib/net\";\nimport { IdentityContext } from \"models/id\";\nimport { useReplies } from \"models/reply\";\nimport { useContext } from \"react\";\nimport Empty from \"./empty\";\nimport PostList from \"./postList\";\n\nexport default function RepliesList() {\n const ident = useContext(IdentityContext);\n const replies = useReplies(ident);\n\n if (!ident || !replies) {\n return null;\n }\n\n const empty = ;\n\n return ;\n}\n"," import type { IProfile } from \"core/types\";\nimport { useIndex, useIsSubscribedTo, useProfile } from \"models/profile\";\nimport Hexatar from \"./hexatar\";\nimport { useNavigate } from \"react-router-dom\";\nimport { hostPrefix } from \"lib/net\";\nimport HexQR from \"./hexQR\";\nimport PostList from \"./postList\";\nimport SubscriberList from \"./subscriberList\";\nimport SubscribeView from \"./subscribeView\";\nimport SubscriptionList from \"./subscriptionList\";\nimport Tabs, { ITab } from \"./tabs\";\nimport Empty from \"./empty\";\nimport { IdentityContext } from \"models/id\";\nimport KnowMore from \"./knowMore\";\nimport RepliesList from \"./repliesList\";\nimport { useContext } from \"react\";\n\nfunction BracketButton({ label, onClick }: { label: string, onClick: () => void }) {\n return [];\n}\n\nfunction ButtonLink({ label, to }: { label: string, to: string }) {\n const navigate = useNavigate();\n return \n}\n\nfunction Handle({ handle, setHandle, editable }: { handle?: string, setHandle: (newHandle: string) => void, editable: boolean}) {\n function handleEdit() {\n const newHandle = prompt(\"New handle\");\n if (!newHandle) {\n return;\n }\n\n setHandle(newHandle);\n }\n\n const emptyText = editable ? \"handle\" : \"No handle\";\n const text = !handle ? emptyText : handle;\n\n return (\n
\n

{text}

\n {editable && }\n
\n );\n}\n\nfunction Bio({ bio, setBio, editable }: { bio?: string, setBio: (newBio: string) => void, editable: boolean }) {\n function handleEdit() {\n const newBio = prompt(\"New bio\");\n if (!newBio) {\n return;\n }\n\n setBio(newBio);\n }\n\n const emptyText = editable ? \"Write a bio, if you like.\" : \"No bio\";\n const text = !bio ? emptyText : bio;\n\n return (\n
\n {text}\n {editable && }\n
\n )\n}\n\nfunction IDCard({ profile, setProfile, id, isAuthedUser }: { profile?: IProfile, setProfile: (newProfile: IProfile) => void, id: string, isAuthedUser: boolean }) {\n if (!profile) {\n return null;\n }\n\n const { handle, bio } = profile;\n\n return (\n
\n \n
\n setProfile({ ...profile, handle: newHandle })} editable={isAuthedUser} />\n setProfile({ ...profile, bio: newBio })} editable={isAuthedUser} />\n
\n
\n );\n}\n\ninterface IProps {\n id: string;\n}\nexport default function Profile({ id }: IProps) {\n const navigate = useNavigate();\n const ident = useContext(IdentityContext);\n const isAuthedUser = ident && id === ident.pubKey.hex;\n\n let host = new URLSearchParams(window.location.search).get(\"host\") ?? undefined;\n\n const [profile, setProfile] = useProfile(id, host);\n const isSubscribed = useIsSubscribedTo(id);\n\n if (!host) {\n host = (profile !== \"notfound\" ? profile?.host : null) ?? hostPrefix;\n }\n\n const index = useIndex(id, host);\n\n if (profile === \"notfound\") {\n return
Not found.
\n }\n\n const emptyPostList = ;\n\n const tabs: ITab[] = [\n {\n name: \"Posts\",\n el: (\n <>\n {isAuthedUser && }\n {\n index === \"notfound\" || !index\n ? emptyPostList\n : \n }\n \n ),\n },\n ];\n\n if (isAuthedUser && ident) {\n tabs.push({\n name: \"Replies\",\n el: ,\n });\n\n tabs.push({\n name: \"Followers\",\n el: ,\n });\n\n tabs.push({\n name: \"Following\",\n el: (\n <>\n \n \n \n ),\n });\n }\n\n return (\n
\n

profile

\n\n \n\n
\n \n \n \n }\n />\n {isAuthedUser && }\n {!isAuthedUser && (isSubscribed ? \"Following\" : )}\n
\n\n \n
\n );\n}\n","import Access from \"../components/access\";\nimport Profile from \"../components/profile\";\nimport { IdentityContext } from \"models/id\";\nimport { useContext } from \"react\";\n\nfunction App() {\n const ident = useContext(IdentityContext);\n\n if (ident === undefined) {\n return null;\n }\n\n const hasAccess = ident?.token != null;\n\n return hasAccess ? (\n ident ? : null\n ) : (\n \n );\n}\n\nexport default App;\n","import { ReportHandler } from 'web-vitals';\n\nconst reportWebVitals = (onPerfEntry?: ReportHandler) => {\n if (onPerfEntry && onPerfEntry instanceof Function) {\n import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {\n getCLS(onPerfEntry);\n getFID(onPerfEntry);\n getFCP(onPerfEntry);\n getLCP(onPerfEntry);\n getTTFB(onPerfEntry);\n });\n }\n};\n\nexport default reportWebVitals;\n","import { useRef, useState } from \"react\";\n\nexport default function CredFields({\n onSubmit,\n fixedCreds,\n ctaText,\n submitEnabledManualOverride,\n}: {\n onSubmit: (username?: string, creds?: string) => void;\n fixedCreds?: string;\n ctaText: string;\n submitEnabledManualOverride?: boolean;\n}) {\n const idFieldRef = useRef(null);\n const credFieldRef = useRef(null);\n\n const [id, setID] = useState(\"\");\n const [creds, setCreds] = useState(\"\");\n function handleIDChange(e: any) {\n setID(e.target.value);\n }\n\n function handleCredsChange(e: any) {\n setCreds(e.target.value);\n }\n\n function handleSubmit(evt: any) {\n evt.preventDefault();\n onSubmit(id, creds);\n }\n\n const missingId = !id;\n const missingCreds = !(fixedCreds ?? creds);\n let submitDisabled = missingId || missingCreds;\n if (submitEnabledManualOverride) {\n submitDisabled = false;\n }\n \n const isLoading = fixedCreds == null;\n\n return (\n
\n \n \n \n \n \n \n );\n}\n","import CredFields from \"components/credFields\";\nimport { useState } from \"react\";\nimport { useLocation, useNavigate } from \"react-router-dom\";\nimport { identify } from \"models/id\";\n\nexport default function LoadCreds() {\n const navigate = useNavigate();\n const location = useLocation();\n const [status, setStatus] = useState(\"\");\n\n const next = new URLSearchParams(location.search).get('next');\n\n async function handleLoad(id?: string, creds?: string) {\n if (!creds) {\n return;\n }\n\n const failed = await identify(creds, setStatus);\n if (failed) {\n return;\n }\n\n navigate(next ? next : \"/\");\n }\n\n return (\n
\n

load

\n

Load credentials from your password manager. If you don't have creds, go back and create some.

\n \n {status}\n
\n );\n}\n","import { ISubReq } from \"core/types\";\nimport EventBus from \"lib/eventBus\";\nimport Net from \"lib/net\";\nimport { useState, useEffect, createContext } from \"react\";\nimport { ID, loadID } from \"./id\";\nimport { addSubscriber } from \"./profile\";\n\ntype Inbox = string[];\n\nlet inbox: Inbox | undefined;\n\nconst inboxChange = new EventBus();\n\nasync function loadInbox(ident: ID, force?: boolean): Promise {\n const shouldRefetch = force || !inbox;\n if (shouldRefetch) {\n const newInbox = await Net.fetchInbox(ident.pubKey.hex, ident.token);\n inbox = newInbox;\n }\n\n return inbox;\n}\n\nexport const InboxContext = createContext(undefined);\n\nexport function useInbox(ident?: ID | null): Inbox | undefined {\n const [inbox, setInbox] = useState();\n useEffect(() => {\n async function reloadInbox() {\n if (!ident) {\n return;\n }\n\n const inb = await loadInbox(ident, true);\n setInbox(inb);\n }\n \n reloadInbox();\n\n inboxChange.on(reloadInbox);\n return () => {\n inboxChange.off(reloadInbox);\n }\n }, [ident]);\n\n return inbox;\n}\n\nexport async function inboxCount(ident: ID): Promise {\n const inbox = await loadInbox(ident);\n\n if (inbox == null) {\n return;\n }\n\n return inbox.length;\n}\n\nexport async function deleteInboxItem(id: string) {\n const ident = await loadID();\n if (!ident) {\n // TODO: show error. Real TODO: rearchitect so ident must be present before calling this.\n return;\n }\n\n // TODO: manage the prefixing with pubkeyhex all on the server side. Client doesn't need to care about that.\n const location = Net.fileLoc(ident.pubKey.hex, `inbox/${id}`);\n try {\n Net.deleteFile(ident.pubKey.hex, ident.token, location);\n inboxChange.emit();\n } catch (err) {\n // TODO: handle in UI code.\n alert(\"Failed to delete.\");\n }\n}\n\nexport async function acceptRequest(id: string, req: ISubReq) {\n await addSubscriber(req);\n return deleteInboxItem(id);\n}\n","import { useContext, useEffect, useState } from \"react\";\nimport { dumpState } from \"lib/storage\";\nimport { useLocation, useNavigate } from \"react-router-dom\";\nimport CredFields from \"components/credFields\";\nimport KnowMore from \"components/knowMore\";\nimport { IdentityContext } from \"models/id\";\nimport { saveAs } from 'file-saver';\n\nfunction More() {\n const [reveal, setReveal] = useState(false);\n const [credState, setCredState] = useState();\n\n useEffect(() => {\n const creds = dumpState();\n if (!creds) {\n return;\n }\n setCredState(creds);\n }, []);\n\n async function handleSave() {\n if (!credState) {\n return;\n }\n\n const blob = new Blob([credState], { type: \"application/json;charset=utf-8\" });\n saveAs(blob, \"id.json\");\n }\n\n const placeholder = credState?.replace(/\\w/g, \"*\");\n\n return (\n
\n

These are your credentials (an ECDSA keypair, etc...). They are pre-populated into the password field, so you can easily store them in your password manager.

\n

To manually save your credentials, use the save button, below.

\n \n
\n \n \n
\n
\n );\n}\n\nfunction CredDumper({ nextURL }: { nextURL: string | undefined }) {\n const [credState, setCredState] = useState();\n const navigate = useNavigate();\n\n useEffect(() => {\n const creds = dumpState();\n if (!creds) {\n return;\n }\n setCredState(creds);\n }, []);\n\n function handleSubmit(username?: string, creds?: string) {\n if (!username || !nextURL) {\n return;\n }\n\n navigate(nextURL);\n }\n\n return (\n
\n

Enter an ID, then hit Save Creds.

\n

This ID is private. It's only used to identify this account in your password manager.

\n

Save in your password manager, when it asks (supports Chrome and Safari; for 1Password, right-click ID field > 1Password > Save Login).

\n\n \n
\n );\n}\n\nexport default function DumpCreds() {\n const ident = useContext(IdentityContext);\n const location = useLocation();\n\n const next = new URLSearchParams(location.search).get(\"next\");\n\n return (\n
\n

credentials

\n \n } />\n
\n );\n}\n","import Profile from \"components/profile\";\nimport { useParams } from \"react-router-dom\";\n\nexport default function UserProfile() {\n const { id } = useParams();\n if (!id) {\n return null;\n }\n\n return ;\n}\n","import { PostVisibility } from \"core/types\";\nimport { useContext, useState } from \"react\";\nimport { Link, useNavigate } from \"react-router-dom\";\nimport KnowMore from \"components/knowMore\";\nimport { publishTextPost } from \"models/post\";\nimport { IdentityContext } from \"models/id\";\nimport { TabBar } from \"components/tabs\";\n\nexport default function Post() {\n const ident = useContext(IdentityContext);\n\n const navigate = useNavigate();\n\n const [text, setText] = useState(\"\");\n\n const [viz, setViz] = useState(\"subs\");\n\n const tabs = [\"Followers\", \"Public\"]\n const activeTab = viz === \"world\" ? \"Public\" : \"Followers\";\n function handleTabSelected(tab: string) {\n if (tab === \"Public\") {\n setViz(\"world\");\n } else if (tab === \"Followers\") {\n setViz(\"subs\");\n }\n }\n \n if (!ident) {\n return
Can't post.
\n }\n\n async function handlePostClicked(visibility: PostVisibility) {\n if (!ident) {\n return;\n }\n\n await publishTextPost(ident, text, visibility);\n\n navigate(`/users/${ident.pubKey.hex}`);\n }\n\n return (\n
\n

post

\n \n setText(e.target.value)}\n className=\"h-48 rounded p-2\"\n />\n \n\n In neopub, all posts are encrypted. For public posts, the encryption key is published. For private posts, the encryption key is separately encrypted for each subscriber, then those are published. See /arch/post to learn more about post security architecture.

\n } />\n
\n );\n}\n","import { useEffect, useState } from \"react\";\nimport { dumpState } from \"lib/storage\";\nimport { Link, useNavigate } from \"react-router-dom\";\nimport CredFields from \"components/credFields\";\nimport KnowMore from \"components/knowMore\";\nimport { deidentify } from \"models/id\";\n\nexport default function Exit() {\n const [credState, setCredState] = useState();\n const navigate = useNavigate();\n\n useEffect(() => {\n setCredState(dumpState());\n }, []);\n\n const [manualOverride, setManualOverride] = useState(false);\n function handleCheck(checked: boolean) {\n setManualOverride(checked);\n }\n\n async function exit() {\n await deidentify();\n navigate(\"/\");\n }\n\n function handleExit(id?: string, creds?: string) {\n if (manualOverride) {\n exit();\n }\n\n if (!creds || !credState) {\n return;\n }\n\n try {\n const credsMatch =\n JSON.stringify(JSON.parse(creds ?? \"\")) ===\n JSON.stringify(JSON.parse(credState ?? \" \"));\n const exitOk = manualOverride || credsMatch;\n if (!exitOk) {\n alert(\"Creds don't match. Try again.\");\n return;\n }\n } catch (e) {\n return;\n }\n\n exit();\n }\n\n return (\n
\n

exit

\n

\n To prove you stored your credentials, use your password manager to fill\n them here.\n

\n\n \n\n \n

\n You should really go to creds to save your credentials.\n

\n

\n If you exit without having stored your creds, there is absolutely no way\n to regain access to your account. Game over, man.\n

\n\n \n \n } />\n
\n );\n}\n","import KnowMore from \"components/knowMore\";\nimport { sendSubRequest } from \"lib/api\";\nimport DB from \"lib/db\";\nimport { hostPrefix } from \"lib/net\";\nimport { mutateState } from \"models/state\";\nimport { addSubscriptionPubKey } from \"lib/storage\";\nimport { follow, useProfile } from \"models/profile\";\nimport { IdentityContext } from \"models/id\";\nimport { useContext, useEffect } from \"react\";\nimport { useState } from \"react\";\nimport { Link, useLocation, useNavigate, useParams } from \"react-router-dom\";\nimport HexIDCard from \"components/hexIdCard\";\n\nexport default function Sub() {\n const navigate = useNavigate();\n const location = useLocation();\n const ident = useContext(IdentityContext);\n const [sentReq, setSentReq] = useState(false);\n\n const params = useParams<\"id\">();\n const pubId = params[\"id\"];\n\n const [following, setFollowing] = useState(false);\n useEffect(() => {\n if (!pubId) {\n return;\n }\n\n DB.subscriptions.get(pubId)\n .then((sub: any) => {\n setFollowing(sub !== undefined);\n });\n }, [pubId]);\n \n const host = hostPrefix;\n const [profile] = useProfile(pubId, host);\n if (!profile || profile === \"notfound\") {\n return
404 Not Found
;\n }\n \n if (!pubId) {\n return null;\n }\n\n async function handleSubscribe() {\n if (!pubId || !navigate || !location || !profile || profile === \"notfound\") {\n return;\n }\n\n if (!ident) {\n alert('You need an identity first.')\n navigate(`/?next=${encodeURIComponent(location.pathname)}`);\n return;\n }\n\n if (ident.pubKey.hex === pubId) {\n alert(\"You can't follow yourself.\");\n return;\n }\n\n const msg = prompt(\"Enter a message to include with the request (optional).\")\n if (msg == null) {\n return;\n }\n\n const worldKeyHex = profile.worldKey;\n\n await sendSubRequest(pubId, ident.pubKey.hex, msg, host, host);\n\n await mutateState(async () => {\n await follow(pubId, profile);\n return addSubscriptionPubKey(pubId, host, worldKeyHex, profile.handle);\n });\n\n setSentReq(true);\n }\n\n return (\n
\n

follow

\n
\n

When you follow someone, you'll get their public posts in your feed.

\n

If they accept your follow request, you'll also see their private posts.

\n
\n\n
\n \n {\n sentReq ?
Sent follow request.
: \n }\n
\n\n \n Read about how following works.\n \n } />\n
\n );\n}","import { Link } from \"react-router-dom\"\n\nexport default function SubArch() {\n return (\n
\n

subscribing

\n
\n

Neopub is designed for a hostile hosting environment.

\n

Encrypting posts prevents the host from reading them.

\n (Read about posting architecture »)\n

Neopub also prevents the host from discovering who follows whom.

\n \"Diagram\n \"Legend\"\n
    \n
  1. A user, the publisher, publishes their public key,
    Ppub
    .
  2. \n
  3. To subscribe to that user, the subscriber first generates an ephemeral key pair,
    (Epub, Epub)
    .
  4. \n
  5. Then, the subscriber uses Diffie-Helman to compute a shared secret, which only the subscriber and publisher are able to compute, by using the ephemeral keypair, and the publisher's public key:
    EDH = DH(Ppub, Epriv)
    .
  6. \n
  7. The subscriber forms the payload of the subscription request by using that shared secret,
    EDH
    , to encrypt their own public key,
    Spub
    , and optionally a message to include with the subscription request:
    Renc = ENC(EDH, Spub ++ M)
    .
  8. \n
  9. The subscriber forms the subscription request by prepending the ephemeral public key to that encrypted payload,
    R = Epub ++ Renc
    .
  10. \n
  11. The subscriber then sends that request to the publisher, using an endpoint the publisher establishes to receive such requests, or through a side channel, such as a messaging app or carrier pigeon.
  12. \n
  13. The publisher's client retrieves that encrypted request from the host, and then decrypts it, by first computing the shared secret,
    EDH = DH(Epub, Ppriv)
    , then using that secret to decrypt the request payload:
    Spub ++ M = DEC(EDH, Renc)
    .
  14. \n
\n

With this architecture, the host is never able to observe the public keys of any of the publisher's subscribers. Only the publisher's client can see those keys, which are the identities of their subscribers. Thus the social graph is end-to-end encrypted.

\n

Neopub accomplishes access control to posts at \"compile time\", by the publisher's client publishing encrypted post keys for each of their subscribers, rather than at run time, by a server enforcing privacy policies. In addition to making the social graph opaque to the host, this architecture prevents server bugs and hacks that grant post access to unintended viewers.

\n
\n
\n );\n}","import { Link } from \"react-router-dom\";\n\nexport default function PostArch() {\n return (\n
\n

posting

\n
\n

In neopub, all posts are encrypted with a \"post key\".

\n

When someone posts publicly, they publish the post key publicly.

\n

When someone posts privately, they encrypt the post key for each of their subscribers, and then publish those wrapped post keys.

\n \"Diagram\n \"Legend\"\n

To read someone's private posts, you must send them a subscription request, and they must accept it. Then you're a subscriber.

\n Read about subscription architecture »\n
\n
\n );\n}","import { Link } from \"react-router-dom\"\n\nexport default function Arch() {\n return (\n
\n

arch

\n\n

Neopub is a social network.

\n\n

Neopub uses pseudonymous identity. Users identify by the public key of a cryptographic public/private keypair. There are no email addresses, no phone numbers, and no passwords.

\n\n

Neopub end-to-end encrypts both the content of posts, and the network structure (links between publishers and subscribers). This minimizes trust in the host.

\n\n \"Diagram\n\n
\n Read about data architecture »\n
\n
\n Read about post security »\n
\n
\n Read about subscription security »\n
\n
\n Read about hosting »\n
\n
\n API docs »\n
\n
\n );\n}","import { Link } from \"react-router-dom\"\n\nexport default function Host() {\n return (\n
\n

hosting

\n\n

Neopub is built for easy self-hosting (for tech-savvy people, at least). Because it's designed for an adversarial hosting environment, with end-to-end encryption (see arch), cloud hosting is fine.

\n\n

Initially, neopub is just built to run on Cloudflare Pages + Workers + KV, but the API is so simple it should be easy to port to other platforms.

\n\n

To host your own neopub node:

\n
    \n
  1. Make a Cloudflare account, at https://www.cloudflare.com.
  2. \n
  3. Make a Github account, at https://www.github.com.
  4. \n
  5. Fork neopub/neopub to your Github account.
  6. \n
  7. Clone that fork to your local machine.
  8. \n
  9. Open a terminal in the
    neopub/workers
    directory.
  10. \n
  11. Set up Cloudflare Wrangler.
  12. \n
  13. Run
    wrangler kv:namespace create neopub
    .
  14. \n
  15. Run
    yarn && wrangler publish
    .
  16. \n
  17. Run
    yarn init:secrets
    .
  18. \n
  19. Create a Cloudflare Pages project, and link it to the forked repo you just made. Configure the \"root directory\" to be
    /frontend
    .
  20. \n
  21. In that Cloudflare Pages project web UI, go to Settings and add an environment variable named \"REACT_APP_HOST_PREFIX\" to the URL of your Cloudflare worker, without the trailing slash.
  22. \n
  23. Retry the Cloudflare Pages deployment, if necessary.
  24. \n
\n
\n );\n}","import Empty from \"components/empty\";\nimport Post from \"components/post\";\nimport { TPost } from \"core/types\";\nimport { IdentityContext } from \"models/id\";\nimport { DBPost, fetchPosts, loadPosts } from \"models/post\";\nimport { useContext, useEffect, useState } from \"react\"\n\nexport default function Feed() {\n const ident = useContext(IdentityContext);\n \n const [posts, setPosts] = useState([])\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n loadPosts().then(setPosts);\n\n if (ident) {\n fetchPosts(ident.privKey.dhKey)\n .then(async () => {\n const posts = await loadPosts();\n setPosts(posts);\n setLoading(false);\n });\n }\n }, [ident]);\n\n if (!ident) {\n return null;\n }\n\n return (\n
\n

feed

\n {loading && (
Loading...
)}\n
\n {posts.map(post => {\n return ;\n })}\n
\n {posts.length < 1 && }\n
\n );\n}\n","import Empty from \"components/empty\";\nimport EncryptedPost from \"components/encryptedPost\";\nimport HexIDCard from \"components/hexIdCard\";\nimport Post from \"components/post\";\nimport ReplyButton from \"components/replyButton\";\nimport Tabs, { ITab } from \"components/tabs\";\nimport DB from \"lib/db\";\nimport { IdentityContext } from \"models/id\";\nimport { deletePost, removeAccess, useAudience } from \"models/post\";\nimport { useProfile } from \"models/profile\";\nimport { useContext, useEffect } from \"react\";\nimport { useState } from \"react\";\nimport { useParams } from \"react-router-dom\";\n\nfunction AudienceListItem({ pubKey, postHash }: { pubKey: string, postHash: string }) {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const [profile, _] = useProfile(pubKey);\n if (profile === \"notfound\" || !profile) {\n return null;\n }\n\n function handleRemove() {\n removeAccess(postHash, pubKey);\n }\n\n return (\n
\n \n \n
\n );\n}\n\nfunction Audience({ postHash, worldKeyHex }: { postHash: string, worldKeyHex?: string }) {\n const pubKeys = useAudience(postHash);\n\n // TODO: visualize all past visibility states, since someone might have cached a key.\n\n return (\n
\n {\n pubKeys.length < 1 && \n }\n {\n pubKeys.map((pubKey) => {\n const isWorld = pubKey === worldKeyHex;\n if (isWorld) {\n return
PUBLIC
;\n }\n\n return ;\n })\n }\n
\n )\n}\n\nexport default function PostDetails() {\n const { userId, postId } = useParams();\n const ident = useContext(IdentityContext);\n\n const [profile] = useProfile(userId);\n\n const [replies, setReplies] = useState([]);\n useEffect(() => {\n DB.posts.where({ replyToHash: postId }).toArray()\n .then((rs: any) => setReplies(rs));\n }, [postId])\n\n if (!(userId && postId)) {\n return null;\n }\n \n if (profile === \"notfound\") {\n return null;\n }\n\n const worldKeyHex = profile?.worldKey ?? (profile as any)?.worldKeyHex; // barf.\n const post = { id: postId };\n\n const postHost = profile?.host;\n\n const isPoster = userId === ident?.pubKey.hex;\n\n function handleDelete() {\n if (!(userId && postId)) {\n return null;\n }\n deletePost(postId);\n }\n\n const tabs: ITab[] = [\n {\n name: \"Replies\",\n el: (\n <>\n {\n replies.map(reply => {\n return \n })\n }\n {\n replies.length < 1 && \n }\n \n ),\n },\n ];\n\n if (isPoster) {\n tabs.push({\n name: \"Audience\",\n el: ,\n });\n }\n\n return (\n
\n

post details

\n \n\n
\n {postHost != null && }\n {isPoster && }\n
\n\n \n
\n )\n}\n","import { Link } from \"react-router-dom\"\n\nexport default function DataArch() {\n return (\n
\n

data model

\n
\n

Neopub has a thick-client architecture. The host does almost no work beyond serving and storing files.

\n

Neopub's data is designed to fit neatly into a filesystem or KV store, so the host doesn't require a relational DB and can run entirely as on-demand \"serverless\" workers (see hosting).

\n

Aside from user profiles, and their lists of posts (\"post indexes\"), all data stored on the host is encrypted end-to-end, before it reaches the host.

\n

To give the experience of a user account that persists across devices, Neopub uses the browser's password manager to transmit private data without storing it on the host.

\n \"Diagram\n

For details on Posts and Post Keys encryption, see /arch/post.

\n

For details on Reqs encryption (subscription requests), see /arch/subs.

\n
\n
\n );\n}","import { ISubReq } from \"core/types\";\nimport { acceptRequest, deleteInboxItem } from \"models/inbox\";\nimport HexIDCard from \"./hexIdCard\";\n\nexport default function Req({ id, req }: { id: string, req: ISubReq}) {\n async function handleAccept() {\n await acceptRequest(id, req);\n }\n\n function handleDelete() {\n deleteInboxItem(id);\n }\n\n return (\n
\n
\n \n
{req.msg}
\n
\n
\n \n \n
\n
\n )\n}\n","import Post from \"components/post\";\nimport { IMessage, IReply, ISubReq } from \"core/types\";\nimport { unwrapInboxItem } from \"models/message\";\nimport { recordReplyInDB } from \"lib/storage\";\nimport { IdentityContext } from \"models/id\";\nimport { useState, useEffect, useContext } from \"react\";\nimport Req from \"./subscriptionRequest\";\n\nexport default function InboxItem({ id, pubKeyHex }: { id: string, pubKeyHex: string }) {\n const ident = useContext(IdentityContext);\n\n // TODO: do all this unwrapping in a data layer. Not UI.\n const [item, setItem] = useState();\n useEffect(() => {\n if (!ident) {\n return;\n }\n unwrapInboxItem(id, pubKeyHex, ident.privKey.dhKey)\n .then(async (item: IMessage | undefined) => {\n if (!item) {\n return;\n }\n\n switch (item.type) {\n case \"reply\":\n await recordReplyInDB(item as IReply);\n break;\n case \"subscribe\":\n break;\n }\n\n setItem(item);\n })\n .catch(err => { console.log(err) });\n }, [id, ident, pubKeyHex]);\n\n if (!item) {\n return null;\n }\n\n switch (item.type) {\n case \"reply\":\n const reply = item as IReply;\n const post = {\n content: {\n text: reply.msg,\n },\n createdAt: new Date(reply.createdAt),\n type: \"text\",\n };\n return \n case \"subscribe\":\n const req = item as ISubReq;\n return ;\n }\n}\n","import Empty from \"components/empty\";\nimport { IdentityContext } from \"models/id\";\nimport { InboxContext } from \"models/inbox\";\nimport { useContext } from \"react\";\nimport InboxItem from \"../components/inboxItem\";\n\nexport default function Inbox() {\n const ident = useContext(IdentityContext);\n const inbox = useContext(InboxContext);\n\n return (\n
\n

inbox

\n {\n ident && inbox && (\n
\n { inbox.map(i => ) }\n
\n )\n }\n {\n inbox && inbox.length < 1 && \n }\n
\n )\n}","import { powHeader, pubKeyHeader, tokenHeader } from \"core/consts\";\n\ninterface IEndpoint {\n method: \"GET\" | \"PUT\" | \"POST\" | \"DELETE\";\n path: string;\n desc: string;\n request: {\n body?: string;\n headers?: IHeader[];\n }\n}\n\ninterface IHeader {\n name: string;\n desc: string;\n}\n\nfunction Endpoint({ endpoint }: { endpoint: IEndpoint }) {\n const { method, path, desc, request } = endpoint;\n const headers = request.headers ?? [];\n\n return (\n
\n

{method} {path}

\n

{desc}

\n {request.body && (\n
\n

Body

\n {request.body}\n
\n )}\n {headers.length > 0 && (\n
\n

Headers

\n \n \n {\n headers.map(({ name, desc }) => {\n return (\n \n \n \n \n );\n })\n }\n \n
{name}{desc}
\n
\n )}\n
\n )\n}\n\nexport default function API() {\n const spec: IEndpoint[] = [\n {\n method: \"POST\",\n path: \"/auth\",\n desc: \"Request a proof-of-work challenge.\",\n request: {\n body: \"JSON describing capabilities that client wants to pay PoW for.\",\n },\n },\n\n {\n method: \"POST\",\n path: \"/chal\",\n desc: \"Trade PoW for user auth token.\",\n request: {\n body: \"PoW solution.\",\n },\n },\n\n {\n method: \"POST\",\n path: \"/inbox\",\n desc: \"Send a message (reply, follow request, ...) to a user's inbox.\",\n request: {\n body: \"Encrypted message.\",\n headers: [\n { name: pubKeyHeader, desc: \"Hex-encoded public key of receipient user.\" },\n { name: powHeader, desc: \"PoW solution.\" },\n ],\n },\n },\n\n {\n method: \"GET\",\n path: \"/inbox\",\n desc: \"Fetch inbox contents.\",\n request: {\n headers: [\n { name: pubKeyHeader, desc: \"Hex-encoded public key of user to fetch inbox of.\" },\n { name: tokenHeader, desc: \"Auth token of user to fetch inbox of.\" },\n ],\n },\n },\n \n {\n method: \"GET\",\n path: \"\",\n desc: \"Fetch the file at . NOTE: this endpoint is not authenticated, because data access security is provided through encryption, not access control.\",\n request: {},\n },\n\n {\n method: \"PUT\",\n path: \"\",\n desc: \"Put a file at for an authenticated user.\",\n request: {\n body: \"Contents of file to put at .\",\n headers: [\n { name: tokenHeader, desc: \"Auth token of user to put file for.\" },\n ],\n },\n },\n\n {\n method: \"DELETE\",\n path: \"\",\n desc: \"Delete the file at for an authenticated user.\",\n request: {\n headers: [\n { name: tokenHeader, desc: \"Auth token of user to delete file for.\" },\n ],\n },\n },\n ]\n return (\n
\n

api

\n\n
\n {\n spec.map(endpoint => {\n const key = `${endpoint.method} ${endpoint.path}`;\n return ;\n })\n }\n
\n
\n );\n}","import React, { useContext } from 'react';\nimport ReactDOM from 'react-dom';\nimport './index.css';\nimport App from './pages/App';\nimport reportWebVitals from './reportWebVitals';\n\nimport {\n BrowserRouter as Router,\n Routes,\n Route,\n Link,\n useLocation,\n} from \"react-router-dom\";\nimport LoadCreds from 'pages/loadCreds';\nimport DumpCreds from 'pages/dumpCreds';\nimport UserProfile from 'pages/userProfile';\nimport Post from 'pages/post';\nimport Exit from './pages/exit';\nimport { isAuthenticated } from 'lib/auth';\nimport Sub from 'pages/sub';\nimport SubArch from 'pages/subArch';\nimport PostArch from 'pages/postArch';\nimport Arch from 'pages/arch';\nimport Host from 'pages/host';\nimport Feed from 'pages/feed';\nimport PostDetails from 'pages/postDetails';\nimport DataArch from 'pages/dataArch';\nimport Inbox from 'pages/inbox';\nimport { InboxContext, useInbox } from 'models/inbox';\nimport { IdentityContext, useID } from 'models/id';\nimport API from 'pages/api';\n\ninterface IMenuItemProps {\n curPath: string;\n path: string;\n text: string;\n}\nfunction MenuItem({ curPath, path, text }: IMenuItemProps) {\n const highlight = curPath === path;\n return {text};\n}\n\nfunction InboxMenuItem({ curPath, path, text }: IMenuItemProps) {\n const highlight = curPath === path;\n const inbox = useContext(InboxContext);\n const count = inbox?.length;\n const showCount = count != null && count > 0;\n\n return (\n \n {text}\n {showCount &&
{count}
}\n \n );\n}\n\ntype MenuItems = Array<{ path: string, text: string, el?: (props: IMenuItemProps) => React.ReactElement }>;\nconst authedMenu: MenuItems = [\n { path: \"/\", text: \"me\" },\n { path: \"/inbox\", text: \"inbox\", el: InboxMenuItem },\n { path: \"/feed\", text: \"feed\" },\n { path: \"/arch\", text: \"arch\" },\n { path: \"/exit\", text: \"exit\" },\n];\n\nconst unauthedMenu: MenuItems = [\n { path: \"/\", text: \"neopub\" },\n { path: \"/arch\", text: \"arch\" },\n];\n\nfunction Menu() {\n const loc = useLocation();\n\n const items: MenuItems = isAuthenticated() ? authedMenu : unauthedMenu;\n\n const kbLink = isAuthenticated() ? \"/post\" : \"/\";\n\n return (\n
\n \"Pixelated\n {\n items.map(({ path, text, el }) => {\n const props = { key: text, path, text, curPath: loc.pathname };\n if (el) {\n return el(props);\n }\n return ;\n })\n }\n
\n )\n}\n\nfunction Main() {\n const ident = useID();\n const inbox = useInbox(ident);\n\n return (\n \n \n \n
\n
\n \n \n \n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n \n \n
\n
\n
\n
\n
\n );\n}\n\nReactDOM.render(\n
,\n document.getElementById('root')\n);\n\n// If you want to start measuring performance in your app, pass a function\n// to log results (for example: reportWebVitals(console.log))\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\nreportWebVitals();\n"],"sourceRoot":""}