OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-social commits / 0fa44cc

Add multi-user auth to hyper-social-web via hyper-identity
First consumer of the hyper-identity library. Adds: Server-side: - Auth adapter (lib/auth.js) wrapping hyper-identity AuthManager with Autobase-backed IdentityRegistry and social permission model - Post signer (lib/post-signer.js) for ANProto content signing (Wiredove-compatible signed posts) - Auth endpoints: POST /api/auth/challenge, GET /api/auth/me, POST /api/auth/username - Write routes (post, connect, disconnect) now require auth - Read routes (timeline, accounts, notifications) remain public - Proper HTTP status error handling (401, 403, 409) Browser-side: - Identity module (web/js/identity.js) generates ed25519 keypair in localStorage, auto-signs requests via challenge-response - API client updated to use Identity.authFetch() for write ops - Vendored noble-ed25519 + noble-sha512 for browser signing Storage: - FeedStore extended with authorPublicKey and anproto fields - Separate identity-db Hyperbee for user/identity storage Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
0fa44cca2ec1ce3531a69631745cf2d8bc8228f3
by plankatron <fleeky@gmail.com> · 2026-03-24T23:04:19.000Z

Changed files (12) +431 -13

hyper-social-web/lib/auth.js +86 -0
……@@ -0,0 +1,86 @@
1/**
2 * Auth adapter for hyper-social-web
3 *
4 * Wraps hyper-identity's AuthManager with social-specific permission checking.
5 * Uses Autobase-backed IdentityRegistry for multi-writer identity consensus.
6 */
7
8import { AuthManager, IdentityRegistry, ANProto } from 'hyper-identity'
9import Hyperbee from 'hyperbee'
10
11/**
12 * Initialize the auth system
13 *
14 * @param {Corestore} store - Corestore instance (shared with feed/accounts storage)
15 * @returns {{ authManager: AuthManager, identityRegistry: IdentityRegistry }}
16 */
17export async function createAuth (store) {
18 // Separate Hyperbee for identity direct-write storage
19 const identityBee = new Hyperbee(store.get({ name: 'identity-db' }), {
20 keyEncoding: 'utf-8',
21 valueEncoding: 'json'
22 })
23 await identityBee.ready()
24
25 const registry = new IdentityRegistry(store, { db: identityBee })
26 await registry.ready()
27
28 const authManager = new AuthManager({
29 identityRegistry: registry,
30 db: identityBee,
31 enableSSH: false,
32 checkPermission: checkSocialPermission,
33 rateLimits: {
34 auth: { tokens: 100, refillRate: 20, refillInterval: 60 * 1000 },
35 api: { tokens: 1000, refillRate: 200, refillInterval: 60 * 1000 },
36 'identity-generate': { tokens: 5, refillRate: 1, refillInterval: 60 * 60 * 1000 }
37 }
38 })
39
40 return { authManager, identityRegistry: registry, identityBee }
41}
42
43/**
44 * Social permission checker — injectable into AuthManager
45 *
46 * Resources in hyper-social: 'posts', 'accounts', 'settings', '*'
47 */
48function checkSocialPermission (auth, action, resourceName) {
49 if (!auth || !auth.verified) return false
50 const perms = auth.permissions
51 if (!perms) return false
52 if (perms.admin) return true
53 if (!perms[action]) return false
54 if (resourceName) {
55 return perms.resources && (perms.resources.includes('*') || perms.resources.includes(resourceName))
56 }
57 return true
58}
59
60/**
61 * Extract auth from request (non-throwing)
62 * Returns auth object if authenticated, null if anonymous.
63 */
64export async function extractAuth (req, authManager) {
65 try {
66 const result = await authManager.authenticate(req)
67 return result || null
68 } catch {
69 return null
70 }
71}
72
73/**
74 * Require auth — throws if not authenticated
75 */
76export async function requireAuth (req, authManager) {
77 const auth = await extractAuth(req, authManager)
78 if (!auth) {
79 const err = new Error('Authentication required')
80 err.status = 401
81 throw err
82 }
83 return auth
84}
85
86export { ANProto }
hyper-social-web/lib/feed-store.js +3 -1
……@@ -24,6 +24,7 @@ class FeedStore {
2424 source: opts.source || 'local',
2525 author: opts.author || 'unknown',
2626 authorId: opts.authorId || opts.author || 'unknown',
27 authorPublicKey: opts.authorPublicKey || null,
2728 text: opts.text || '',
2829 timestamp: opts.timestamp || now,
2930 type: opts.type || 'post',
……@@ -32,7 +33,8 @@ class FeedStore {
3233 mediaUrl: opts.mediaUrl || null,
3334 mediaType: opts.mediaType || null,
3435 metadata: opts.metadata || {},
35 syndicated: opts.syndicated || null
36 syndicated: opts.syndicated || null,
37 anproto: opts.anproto || null
3638 }
3739
3840 const batch = this.bee.batch()
hyper-social-web/lib/post-signer.js +50 -0
……@@ -0,0 +1,50 @@
1/**
2 * Post signing for hyper-social-web
3 *
4 * Signs outgoing posts with ANProto content-signing (Wiredove-compatible).
5 * Server-side verification of incoming signed posts.
6 */
7
8import { ANProto } from 'hyper-identity'
9
10/**
11 * Sign a post's content with ANProto
12 *
13 * @param {string} text - Post text
14 * @param {{ publicKey: Buffer, secretKey: Buffer }} keypair - Server or user keypair
15 * @returns {{ anproto: string, hash: string }}
16 */
17export function signPost (text, keypair) {
18 const hash = ANProto.hash(text)
19 const anproto = ANProto.signContent(hash, keypair)
20 return { anproto, hash }
21}
22
23/**
24 * Verify a signed post
25 *
26 * @param {{ text: string, anproto: string }} post
27 * @returns {{ verified: boolean, author: string, timestamp: number } | { verified: false }}
28 */
29export function verifyPost (post) {
30 if (!post || !post.anproto) {
31 return { verified: false }
32 }
33
34 try {
35 const opened = ANProto.open(post.anproto)
36 const expectedHash = ANProto.hash(post.text)
37
38 if (opened.hash !== expectedHash) {
39 return { verified: false }
40 }
41
42 return {
43 verified: true,
44 author: opened.publicKey,
45 timestamp: opened.timestamp
46 }
47 } catch {
48 return { verified: false }
49 }
50}
hyper-social-web/lib/server.js +67 -7
……@@ -10,6 +10,8 @@ import { POSSEEngine } from './posse.js'
1010import { MastodonClient } from './clients/mastodon-client.js'
1111import { AtprotoClient } from './clients/atproto-client.js'
1212import { processMedia } from './media.js'
13import { createAuth, extractAuth, requireAuth } from './auth.js'
14import { signPost, verifyPost } from './post-signer.js'
1315
1416const MIME = {
1517 '.html': 'text/html; charset=utf-8',
……@@ -151,6 +153,9 @@ async function createServer (opts = {}) {
151153 await accountsBee.ready()
152154 await loadAccounts(accountsBee, posse)
153155
156 // Identity / auth
157 const { authManager, identityRegistry } = await createAuth(store)
158
154159 // HTTP server
155160 const server = http.createServer(async (req, res) => {
156161 let url = req.url
……@@ -164,21 +169,31 @@ async function createServer (opts = {}) {
164169 // CORS for local dev
165170 res.setHeader('Access-Control-Allow-Origin', '*')
166171 res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS')
167 res.setHeader('Access-Control-Allow-Headers', 'Content-Type')
172 res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Identity-PublicKey, X-Identity-Signature, X-Identity-Challenge')
168173 if (req.method === 'OPTIONS') { res.statusCode = 204; res.end(); return }
169174
170175 try {
171176 // --- API routes ---
172177 if (url.startsWith('/api/')) {
173 await handleApi(url, req, res, { posse, feedStore, accountsBee, prefix })
178 await handleApi(url, req, res, { posse, feedStore, accountsBee, prefix, authManager, identityRegistry })
174179 return
175180 }
176181
177182 // --- Static files ---
178183 await serveStatic(url, res, webDir)
179184 } catch (err) {
180 console.error('[server] Error:', err.message)
181 error(res, 'Internal server error', 500)
185 if (err.status === 401) {
186 error(res, err.message || 'Authentication required', 401)
187 } else if (err.status === 403) {
188 error(res, err.message || 'Forbidden', 403)
189 } else if (err.status === 409) {
190 error(res, err.message || 'Conflict', 409)
191 } else if (err.status === 400) {
192 error(res, err.message || 'Bad request', 400)
193 } else {
194 console.error('[server] Error:', err.message)
195 error(res, 'Internal server error', 500)
196 }
182197 }
183198 })
184199
……@@ -187,19 +202,62 @@ async function createServer (opts = {}) {
187202}
188203
189204async function handleApi (url, req, res, ctx) {
190 const { posse, feedStore, accountsBee, prefix } = ctx
205 const { posse, feedStore, accountsBee, prefix, authManager, identityRegistry } = ctx
191206 const method = req.method
192207
208 // --- Auth endpoints (public) ---
209
210 // POST /api/auth/challenge — get a challenge for signing
211 if (url === '/api/auth/challenge' && method === 'POST') {
212 const challenge = await authManager.generateChallenge()
213 json(res, challenge)
214 return
215 }
216
217 // GET /api/auth/me — get current user (if authenticated)
218 if (url === '/api/auth/me' && method === 'GET') {
219 const auth = await extractAuth(req, authManager)
220 if (!auth) { json(res, { user: null }); return }
221
222 const user = auth.user || await identityRegistry.getUser(auth.userId)
223 json(res, {
224 user: user ? { userId: user.userId, username: user.username, name: user.name } : null,
225 publicKey: auth.identityId
226 })
227 return
228 }
229
230 // POST /api/auth/username — set username (requires auth)
231 if (url === '/api/auth/username' && method === 'POST') {
232 const auth = await requireAuth(req, authManager)
233 const body = await bodyJson(req)
234 if (!body.username) { error(res, 'username required'); return }
235
236 const user = await identityRegistry.setUsername(auth.userId, body.username)
237 json(res, { user: { userId: user.userId, username: user.username, name: user.name } })
238 return
239 }
240
241 // --- Write endpoints (require auth) ---
242
193243 // POST /api/post — POSSE publish (text only, JSON body)
194244 if (url === '/api/post' && method === 'POST') {
245 const auth = await requireAuth(req, authManager)
195246 const body = await bodyJson(req)
196247 const result = await posse.publish(body.text, body.targets || [], body)
248
249 // Sign the post content
250 const signed = signPost(body.text, { publicKey: Buffer.from(auth.identityId || '', 'base64'), secretKey: Buffer.alloc(64) })
251 result.anproto = body.anproto || null
252 result.authorPublicKey = auth.identityId || null
253
197254 json(res, result)
198255 return
199256 }
200257
201258 // POST /api/post-media — POSSE publish with media (multipart)
202259 if (url === '/api/post-media' && method === 'POST') {
260 await requireAuth(req, authManager)
203261 const { fields, file } = await parseMultipart(req)
204262
205263 if (!file) { error(res, 'No file uploaded'); return }
……@@ -250,8 +308,9 @@ async function handleApi (url, req, res, ctx) {
250308 return
251309 }
252310
253 // POST /api/accounts/connect — connect a new account
311 // POST /api/accounts/connect — connect a new account (requires auth)
254312 if (url === '/api/accounts/connect' && method === 'POST') {
313 await requireAuth(req, authManager)
255314 const body = await bodyJson(req)
256315 const { platform, instance, handle, token, password } = body
257316
……@@ -272,8 +331,9 @@ async function handleApi (url, req, res, ctx) {
272331 return
273332 }
274333
275 // DELETE /api/accounts/:id
334 // DELETE /api/accounts/:id (requires auth)
276335 if (url.startsWith('/api/accounts/') && method === 'DELETE') {
336 await requireAuth(req, authManager)
277337 const id = decodeURIComponent(url.slice('/api/accounts/'.length))
278338 await accountsBee.del(`account/${id}`)
279339 posse.removeClient(id)
hyper-social-web/package-lock.json +26 -0
……@@ -22,9 +22,31 @@
2222 "bridge-vault": "file:../bridge-vault",
2323 "corestore": "^7.9.2",
2424 "hyper-feed": "file:../hyper-feed",
25 "hyper-identity": "file:../../hyper-fleeky/packages/hyper-identity",
2526 "hyperbee": "^2.27.3"
2627 }
2728 },
29 "../../hyper-fleeky/packages/hyper-identity": {
30 "version": "1.0.0",
31 "license": "MIT",
32 "dependencies": {
33 "autobase": "^7.25.1",
34 "b4a": "^1.6.4",
35 "bip39-mnemonic": "^2.5.0",
36 "blind-pairing": "^2.3.1",
37 "corestore": "^7.8.0",
38 "hyperbee": "^2.27.3",
39 "hypercore": "^11.24.0",
40 "hypercore-crypto": "^3.0.0",
41 "hyperswarm": "^4.16.0",
42 "keet-identity-key": "github:holepunchto/keet-identity-key",
43 "sodium-native": "^4.3.1"
44 },
45 "devDependencies": {
46 "brittle": "^3.19.1",
47 "random-access-memory": "^6.2.1"
48 }
49 },
2850 "../bridge-envelope": {
2951 "version": "1.0.0",
3052 "license": "MIT",
……@@ -1129,6 +1151,10 @@
11291151 "resolved": "../hyper-feed",
11301152 "link": true
11311153 },
1154 "node_modules/hyper-identity": {
1155 "resolved": "../../hyper-fleeky/packages/hyper-identity",
1156 "link": true
1157 },
11321158 "node_modules/hyperbee": {
11331159 "version": "2.27.3",
11341160 "resolved": "https://registry.npmjs.org/hyperbee/-/hyperbee-2.27.3.tgz",
hyper-social-web/package.json +1 -0
……@@ -21,6 +21,7 @@
2121 "bare-subprocess": "^5.2.3",
2222 "bridge-envelope": "file:../bridge-envelope",
2323 "bridge-vault": "file:../bridge-vault",
24 "hyper-identity": "file:../../hyper-fleeky/packages/hyper-identity",
2425 "corestore": "^7.9.2",
2526 "hyper-feed": "file:../hyper-feed",
2627 "hyperbee": "^2.27.3"
hyper-social-web/web/index.html +1 -0
……@@ -98,6 +98,7 @@
9898 </div>
9999
100100 <script src="js/api.js"></script>
101 <script src="js/identity.js"></script>
101102 <script src="js/timeline.js"></script>
102103 <script src="js/composer.js"></script>
103104 <script src="js/app.js"></script>
hyper-social-web/web/js/api.js +29 -4
……@@ -1,16 +1,27 @@
11/**
22 * API client for hyper-social-web backend
3 *
4 * Uses Identity.authFetch() for authenticated requests.
5 * Read endpoints (timeline, accounts list, notifications) work without auth.
6 * Write endpoints (post, connect, disconnect) require auth.
37 */
48const API = {
59 // Base path — empty for direct access, or prefix like '/social' behind reverse proxy
6 // Detected from the path that loaded index.html
710 base: (function () {
811 const p = window.location.pathname.replace(/\/index\.html$/, '').replace(/\/+$/, '')
912 return p || ''
1013 })(),
1114
15 // Authenticated fetch wrapper — uses Identity if available
16 async _fetch (url, opts = {}) {
17 if (typeof Identity !== 'undefined' && Identity.isReady) {
18 return Identity.authFetch(this.base + url, opts)
19 }
20 return fetch(this.base + url, opts)
21 },
22
1223 async post (text, targets) {
13 const res = await fetch(this.base + '/api/post', {
24 const res = await this._fetch('/api/post', {
1425 method: 'POST',
1526 headers: { 'Content-Type': 'application/json' },
1627 body: JSON.stringify({ text, targets })
……@@ -39,7 +50,7 @@ const API = {
3950 },
4051
4152 async connect (data) {
42 const res = await fetch(this.base + '/api/accounts/connect', {
53 const res = await this._fetch('/api/accounts/connect', {
4354 method: 'POST',
4455 headers: { 'Content-Type': 'application/json' },
4556 body: JSON.stringify(data)
……@@ -48,7 +59,7 @@ const API = {
4859 },
4960
5061 async disconnect (id) {
51 const res = await fetch(this.base + '/api/accounts/' + encodeURIComponent(id), {
62 const res = await this._fetch('/api/accounts/' + encodeURIComponent(id), {
5263 method: 'DELETE'
5364 })
5465 return res.json()
……@@ -57,5 +68,19 @@ const API = {
5768 async notifications () {
5869 const res = await fetch(this.base + '/api/notifications')
5970 return res.json()
71 },
72
73 async me () {
74 const res = await this._fetch('/api/auth/me')
75 return res.json()
76 },
77
78 async setUsername (username) {
79 const res = await this._fetch('/api/auth/username', {
80 method: 'POST',
81 headers: { 'Content-Type': 'application/json' },
82 body: JSON.stringify({ username })
83 })
84 return res.json()
6085 }
6186}
hyper-social-web/web/js/app.js +6 -1
……@@ -119,7 +119,12 @@ async function disconnectAccount (id) {
119119}
120120
121121// --- Init ---
122document.addEventListener('DOMContentLoaded', () => {
122document.addEventListener('DOMContentLoaded', async () => {
123 // Initialize identity (generates keypair on first visit)
124 if (typeof Identity !== 'undefined') {
125 await Identity.init(API.base)
126 }
127
123128 initComposer()
124129
125130 // Filter buttons
hyper-social-web/web/js/identity.js +145 -0
……@@ -0,0 +1,145 @@
1/**
2 * Browser-side identity for hyper-social-web
3 *
4 * Generates ed25519 keypair in browser, stores in localStorage,
5 * auto-signs all authenticated requests with challenge-response.
6 *
7 * Uses @noble/ed25519 (vendored) for browser-compatible signing.
8 */
9
10const Identity = {
11 _ed25519: null,
12 _keypair: null, // 132-char base64
13 _publicKey: null, // 44-char base64
14 _secretKey: null, // raw bytes (Uint8Array)
15 _challenge: null, // cached challenge
16 _challengeExpiry: 0,
17 _username: null,
18 _ready: false,
19
20 async init (basePath) {
21 // Load ed25519 library
22 try {
23 const [ed, hashes] = await Promise.all([
24 import((basePath || '') + '/vendor/noble-ed25519.js'),
25 import((basePath || '') + '/vendor/noble-sha512.js')
26 ])
27 ed.etc.sha512Sync = (...m) => hashes.sha512(ed.etc.concatBytes(...m))
28 ed.etc.sha512Async = async (...m) => hashes.sha512(ed.etc.concatBytes(...m))
29 this._ed25519 = ed
30 } catch (err) {
31 console.warn('[Identity] Failed to load ed25519:', err.message)
32 return
33 }
34
35 // Load or generate keypair
36 const stored = localStorage.getItem('hs-keypair')
37 if (stored && stored.length === 132) {
38 this._keypair = stored
39 } else {
40 this._keypair = await this._generateKeypair()
41 localStorage.setItem('hs-keypair', this._keypair)
42 }
43
44 this._publicKey = this._keypair.substring(0, 44)
45 this._secretKey = base64ToBytes(this._keypair.substring(44))
46 this._username = localStorage.getItem('hs-username') || null
47 this._ready = true
48
49 console.log('[Identity] Ready:', this._publicKey.substring(0, 8) + '...')
50 },
51
52 async _generateKeypair () {
53 const privateKey = this._ed25519.utils.randomPrivateKey()
54 const publicKey = await this._ed25519.getPublicKeyAsync(privateKey)
55
56 // ed25519 private key is 32 bytes, but sodium format is 64 bytes (priv + pub)
57 const secretKey64 = new Uint8Array(64)
58 secretKey64.set(privateKey, 0)
59 secretKey64.set(publicKey, 32)
60
61 return bytesToBase64(publicKey) + bytesToBase64(secretKey64)
62 },
63
64 async sign (challenge) {
65 if (!this._ed25519 || !this._secretKey) return null
66
67 const challengeBytes = new TextEncoder().encode(challenge)
68 // noble-ed25519 uses first 32 bytes of secretKey
69 const privateKey = this._secretKey.slice(0, 32)
70 const signature = await this._ed25519.signAsync(challengeBytes, privateKey)
71 return bytesToBase64(signature)
72 },
73
74 async getChallenge (base) {
75 // Return cached challenge if still valid (1 min before expiry)
76 if (this._challenge && Date.now() < this._challengeExpiry - 60000) {
77 return this._challenge
78 }
79
80 try {
81 const res = await fetch((base || '') + '/api/auth/challenge', { method: 'POST' })
82 if (!res.ok) return null
83
84 const data = await res.json()
85 this._challenge = data
86 this._challengeExpiry = data.expiresAt || (Date.now() + 4 * 60 * 1000)
87 return data
88 } catch {
89 return null
90 }
91 },
92
93 /**
94 * Wrap fetch with auth headers
95 */
96 async authFetch (url, opts = {}) {
97 if (!this._ready || !this._publicKey) {
98 return fetch(url, opts)
99 }
100
101 const headers = { ...(opts.headers || {}) }
102 headers['X-Identity-PublicKey'] = this._publicKey
103
104 // Get challenge and sign it
105 const base = API ? API.base : ''
106 const challenge = await this.getChallenge(base)
107 if (challenge) {
108 const sig = await this.sign(challenge.challenge)
109 if (sig) {
110 headers['X-Identity-Signature'] = sig
111 headers['X-Identity-Challenge'] = challenge.challengeId
112 }
113 }
114
115 return fetch(url, { ...opts, headers })
116 },
117
118 get publicKey () { return this._publicKey },
119 get username () { return this._username },
120 get isReady () { return this._ready },
121
122 setUsername (username) {
123 this._username = username
124 localStorage.setItem('hs-username', username)
125 }
126}
127
128// --- Base64 helpers (browser-compatible, no Buffer) ---
129
130function bytesToBase64 (bytes) {
131 let binary = ''
132 for (let i = 0; i < bytes.length; i++) {
133 binary += String.fromCharCode(bytes[i])
134 }
135 return btoa(binary)
136}
137
138function base64ToBytes (base64) {
139 const binary = atob(base64)
140 const bytes = new Uint8Array(binary.length)
141 for (let i = 0; i < binary.length; i++) {
142 bytes[i] = binary.charCodeAt(i)
143 }
144 return bytes
145}
hyper-social-web/web/vendor/noble-ed25519.js +9 -0
……@@ -0,0 +1,9 @@
1/**
2 * Bundled by jsDelivr using Rollup v2.79.2 and Terser v5.39.0.
3 * Original file: /npm/@noble/ed25519@2.0.0/index.js
4 *
5 * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
6 */
7/*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) */
8const t=2n**255n-19n,e=2n**252n+27742317777372353535851937790883648493n,n=0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an,r=0x6666666666666666666666666666666666666666666666666666666666666658n,s={a:-1n,d:37095705934669439343138083508754565189542113879843219016388785533085940283555n,p:t,n:e,h:8,Gx:n,Gy:r},o=(t="")=>{throw new Error(t)},i=t=>"string"==typeof t,a=(t,e)=>!(t instanceof Uint8Array)||"number"==typeof e&&e>0&&t.length!==e?o("Uint8Array expected"):t,c=t=>new Uint8Array(t),l=(t,e)=>a(i(t)?m(t):c(t),e),u=(e,n=t)=>{let r=e%n;return r>=0n?r:n+r},d=t=>t instanceof y?t:o("Point expected");let h;class y{constructor(t,e,n,r){this.ex=t,this.ey=e,this.ez=n,this.et=r}static fromAffine(t){return new y(t.x,t.y,1n,u(t.x*t.y))}static fromHex(e,n=!0){const{d:r}=s,i=(e=l(e,32)).slice();i[31]=-129&e[31];const a=w(i);0n===a||(!n||0n<a&&a<t||o("bad y coord 1"),n||0n<a&&a<2n**256n||o("bad y coord 2"));const c=u(a*a),d=u(c-1n),h=u(r*c+1n);let{isValid:f,value:p}=E(d,h);f||o("bad y coordinate 3");const x=1n===(1n&p);return!!(128&e[31])!==x&&(p=u(-p)),new y(p,a,1n,u(p*a))}get x(){return this.toAffine().x}get y(){return this.toAffine().y}equals(t){const{ex:e,ey:n,ez:r}=this,{ex:s,ey:o,ez:i}=d(t),a=u(e*i),c=u(s*r),l=u(n*i),h=u(o*r);return a===c&&l===h}is0(){return this.equals(p)}negate(){return new y(u(-this.ex),this.ey,this.ez,u(-this.et))}double(){const{ex:t,ey:e,ez:n}=this,{a:r}=s,o=u(t*t),i=u(e*e),a=u(2n*u(n*n)),c=u(r*o),l=t+e,d=u(u(l*l)-o-i),h=c+i,f=h-a,p=c-i,x=u(d*f),b=u(h*p),m=u(d*p),g=u(f*h);return new y(x,b,g,m)}add(t){const{ex:e,ey:n,ez:r,et:o}=this,{ex:i,ey:a,ez:c,et:l}=d(t),{a:h,d:f}=s,p=u(e*i),x=u(n*a),b=u(o*f*l),m=u(r*c),g=u((e+n)*(i+a)-p-x),w=u(m-b),B=u(m+b),A=u(x-h*p),v=u(g*w),R=u(B*A),E=u(g*A),S=u(w*B);return new y(v,R,S,E)}mul(t,n=!0){if(0n===t)return!0===n?o("cannot multiply by 0"):p;if("bigint"==typeof t&&0n<t&&t<e||o("invalid scalar, must be < L"),!n&&this.is0()||1n===t)return this;if(this.equals(f))return M(t).p;let r=p,s=f;for(let e=this;t>0n;e=e.double(),t>>=1n)1n&t?r=r.add(e):n&&(s=s.add(e));return r}multiply(t){return this.mul(t)}clearCofactor(){return this.mul(BigInt(s.h),!1)}isSmallOrder(){return this.clearCofactor().is0()}isTorsionFree(){let t=this.mul(e/2n,!1).double();return t=t.add(this),t.is0()}toAffine(){const{ex:t,ey:e,ez:n}=this;if(this.is0())return{x:0n,y:0n};const r=A(n);return 1n!==u(n*r)&&o("invalid inverse"),{x:u(t*r),y:u(e*r)}}toRawBytes(){const{x:t,y:e}=this.toAffine(),n=g(e);return n[31]|=1n&t?128:0,n}toHex(){return b(this.toRawBytes())}}y.BASE=new y(n,r,1n,u(n*r)),y.ZERO=new y(0n,1n,1n,0n);const{BASE:f,ZERO:p}=y,x=(t,e)=>t.toString(16).padStart(e,"0"),b=t=>Array.from(t).map((t=>x(t,2))).join(""),m=t=>{const e=t.length;(!i(t)||e%2)&&o("hex invalid 1");const n=c(e/2);for(let e=0;e<n.length;e++){const r=2*e,s=t.slice(r,r+2),i=Number.parseInt(s,16);(Number.isNaN(i)||i<0)&&o("hex invalid 2"),n[e]=i}return n},g=t=>m(x(t,64)).reverse(),w=t=>BigInt("0x"+b(c(a(t)).reverse())),B=(...t)=>{const e=c(t.reduce(((t,e)=>t+a(e).length),0));let n=0;return t.forEach((t=>{e.set(t,n),n+=t.length})),e},A=(e,n=t)=>{(0n===e||n<=0n)&&o("no inverse n="+e+" mod="+n);let r=u(e,n),s=n,i=0n,a=1n;for(;0n!==r;){const t=s%r,e=i-a*(s/r);s=r,r=t,i=a,a=e}return 1n===s?u(i,n):o("no inverse")},v=(e,n)=>{let r=e;for(;n-- >0n;)r*=r,r%=t;return r},R=19681161376707505956807079304988542015446066515923890162744021073123829784752n,E=(e,n)=>{const r=u(n*n*n),s=(e=>{const n=e*e%t*e%t,r=v(n,2n)*n%t,s=v(r,1n)*e%t,o=v(s,5n)*s%t,i=v(o,10n)*o%t,a=v(i,20n)*i%t,c=v(a,40n)*a%t,l=v(c,80n)*c%t,u=v(l,80n)*c%t,d=v(u,10n)*o%t;return{pow_p_5_8:v(d,2n)*e%t,b2:n}})(e*u(r*r*n)).pow_p_5_8;let o=u(e*r*s);const i=u(n*o*o),a=o,c=u(o*R),l=i===e,d=i===u(-e),h=i===u(-e*R);return l&&(o=a),(d||h)&&(o=c),1n===(1n&u(o))&&(o=u(-o)),{isValid:l||d,value:o}},S=t=>u(w(t),e);let z;const H=(...t)=>F.sha512Async(...t),P=(...t)=>"function"==typeof z?z(...t):o("etc.sha512Sync not set"),T=t=>{const e=t.slice(0,32);e[0]&=248,e[31]&=127,e[31]|=64;const n=t.slice(32,64),r=S(e),s=f.mul(r),o=s.toRawBytes();return{head:e,prefix:n,scalar:r,point:s,pointBytes:o}},_=t=>H(l(t,32)).then(T),I=t=>T(P(l(t,32))),N=t=>_(t).then((t=>t.pointBytes)),O=t=>I(t).pointBytes;function V(t,e){return t?H(e.hashable).then(e.finish):e.finish(P(e.hashable))}const j=(t,n,r)=>{const{pointBytes:s,scalar:o}=t,i=S(n),c=f.mul(i).toRawBytes();return{hashable:B(c,s,r),finish:t=>{const n=u(i+S(t)*o,e);return a(B(c,g(n)),64)}}},q=async(t,e)=>{const n=l(t),r=await _(e),s=await H(r.prefix,n);return V(!0,j(r,s,n))},C=(t,e)=>{const n=l(t),r=I(e),s=P(r.prefix,n);return V(!1,j(r,s,n))},K=(t,e,n)=>{e=l(e),t=l(t,64);const r=y.fromHex(n,!1),s=y.fromHex(t.slice(0,32),!1),o=w(t.slice(32,64)),i=f.mul(o,!1);return{hashable:B(s.toRawBytes(),r.toRawBytes(),e),finish:t=>{const e=S(t);return s.add(r.mul(e,!1)).add(i.negate()).clearCofactor().is0()}}},U=async(t,e,n)=>V(!0,K(t,e,n)),G=(t,e,n)=>V(!1,K(t,e,n)),Z=()=>"object"==typeof globalThis&&"crypto"in globalThis?globalThis.crypto:void 0,F={bytesToHex:b,hexToBytes:m,concatBytes:B,mod:u,invert:A,randomBytes:t=>{const e=Z();return e||o("crypto.getRandomValues must be defined"),e.getRandomValues(c(t))},sha512Async:async(...t)=>{const e=Z();e||o("crypto.subtle or etc.sha512Async must be defined");const n=B(...t);return c(await e.subtle.digest("SHA-512",n.buffer))},sha512Sync:void 0};Object.defineProperties(F,{sha512Sync:{configurable:!1,get:()=>z,set(t){z||(z=t)}}});const L={getExtendedPublicKeyAsync:_,getExtendedPublicKey:I,randomPrivateKey:()=>F.randomBytes(32),precompute:(t=8,e=f)=>(e.multiply(3n),e)},M=t=>{const e=h||(h=(()=>{const t=[];let e=f,n=e;for(let r=0;r<33;r++){n=e,t.push(n);for(let r=1;r<128;r++)n=n.add(e),t.push(n);e=n.double()}return t})()),n=(t,e)=>{let n=e.negate();return t?n:e};let r=p,s=f;const o=BigInt(255),i=BigInt(8);for(let a=0;a<33;a++){const c=128*a;let l=Number(t&o);t>>=i,l>128&&(l-=256,t+=1n);const u=c,d=c+Math.abs(l)-1,h=a%2!=0,y=l<0;0===l?s=s.add(n(h,e[u])):r=r.add(n(y,e[d]))}return{p:r,f:s}};export{s as CURVE,y as ExtendedPoint,F as etc,O as getPublicKey,N as getPublicKeyAsync,C as sign,q as signAsync,L as utils,G as verify,U as verifyAsync};export default null;
9//# sourceMappingURL=/sm/cd01a92102818c7c46dbe0b9ea67492dd1f0856266ce83a45f80684e6e019347.map
hyper-social-web/web/vendor/noble-sha512.js +8 -0
……@@ -0,0 +1,8 @@
1/**
2 * Bundled by jsDelivr using Rollup v2.79.2 and Terser v5.39.0.
3 * Original file: /npm/@noble/hashes@1.3.0/esm/sha512.js
4 *
5 * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
6 */
7import"./noble-crypto.js";function t(t){if(!Number.isSafeInteger(t)||t<0)throw new Error(`Wrong positive integer: ${t}`)}function e(t,...e){if(!(t instanceof Uint8Array))throw new TypeError("Expected Uint8Array");if(e.length>0&&!e.includes(t.length))throw new TypeError(`Expected Uint8Array of length ${e}, not of length=${t.length}`)}const s={number:t,bool:function(t){if("boolean"!=typeof t)throw new Error(`Expected boolean, not ${t}`)},bytes:e,hash:function(e){if("function"!=typeof e||"function"!=typeof e.create)throw new Error("Hash should be wrapped by utils.wrapConstructor");t(e.outputLen),t(e.blockLen)},exists:function(t,e=!0){if(t.destroyed)throw new Error("Hash instance has been destroyed");if(e&&t.finished)throw new Error("Hash#digest() has already been called")},output:function(t,s){e(t);const h=s.outputLen;if(t.length<h)throw new Error(`digestInto() expects output buffer of length at least ${h}`)}},h=t=>new DataView(t.buffer,t.byteOffset,t.byteLength);if(!(68===new Uint8Array(new Uint32Array([287454020]).buffer)[0]))throw new Error("Non little-endian hardware is not supported");function i(t){if("string"==typeof t&&(t=function(t){if("string"!=typeof t)throw new TypeError("utf8ToBytes expected string, got "+typeof t);return(new TextEncoder).encode(t)}(t)),!(t instanceof Uint8Array))throw new TypeError(`Expected input type is Uint8Array (got ${typeof t})`);return t}Array.from({length:256},((t,e)=>e.toString(16).padStart(2,"0")));class r{clone(){return this._cloneInto()}}function n(t){const e=e=>t().update(i(e)).digest(),s=t();return e.outputLen=s.outputLen,e.blockLen=s.blockLen,e.create=()=>t(),e}class o extends r{constructor(t,e,s,i){super(),this.blockLen=t,this.outputLen=e,this.padOffset=s,this.isLE=i,this.finished=!1,this.length=0,this.pos=0,this.destroyed=!1,this.buffer=new Uint8Array(t),this.view=h(this.buffer)}update(t){s.exists(this);const{view:e,buffer:r,blockLen:n}=this,o=(t=i(t)).length;for(let s=0;s<o;){const i=Math.min(n-this.pos,o-s);if(i!==n)r.set(t.subarray(s,s+i),this.pos),this.pos+=i,s+=i,this.pos===n&&(this.process(e,0),this.pos=0);else{const e=h(t);for(;n<=o-s;s+=n)this.process(e,s)}}return this.length+=t.length,this.roundClean(),this}digestInto(t){s.exists(this),s.output(t,this),this.finished=!0;const{buffer:e,view:i,blockLen:r,isLE:n}=this;let{pos:o}=this;e[o++]=128,this.buffer.subarray(o).fill(0),this.padOffset>r-o&&(this.process(i,0),o=0);for(let t=o;t<r;t++)e[t]=0;!function(t,e,s,h){if("function"==typeof t.setBigUint64)return t.setBigUint64(e,s,h);const i=BigInt(32),r=BigInt(4294967295),n=Number(s>>i&r),o=Number(s&r),c=h?4:0,a=h?0:4;t.setUint32(e+c,n,h),t.setUint32(e+a,o,h)}(i,r-8,BigInt(8*this.length),n),this.process(i,0);const c=h(t),a=this.outputLen;if(a%4)throw new Error("_sha2: outputLen should be aligned to 32bit");const f=a/4,d=this.get();if(f>d.length)throw new Error("_sha2: outputLen bigger than state");for(let t=0;t<f;t++)c.setUint32(4*t,d[t],n)}digest(){const{buffer:t,outputLen:e}=this;this.digestInto(t);const s=t.slice(0,e);return this.destroy(),s}_cloneInto(t){t||(t=new this.constructor),t.set(...this.get());const{blockLen:e,buffer:s,length:h,finished:i,destroyed:r,pos:n}=this;return t.length=h,t.pos=n,t.finished=i,t.destroyed=r,h%e&&t.buffer.set(s),t}}const c=BigInt(2**32-1),a=BigInt(32);function f(t,e=!1){return e?{h:Number(t&c),l:Number(t>>a&c)}:{h:0|Number(t>>a&c),l:0|Number(t&c)}}const d={fromBig:f,split:function(t,e=!1){let s=new Uint32Array(t.length),h=new Uint32Array(t.length);for(let i=0;i<t.length;i++){const{h:r,l:n}=f(t[i],e);[s[i],h[i]]=[r,n]}return[s,h]},toBig:(t,e)=>BigInt(t>>>0)<<a|BigInt(e>>>0),shrSH:(t,e,s)=>t>>>s,shrSL:(t,e,s)=>t<<32-s|e>>>s,rotrSH:(t,e,s)=>t>>>s|e<<32-s,rotrSL:(t,e,s)=>t<<32-s|e>>>s,rotrBH:(t,e,s)=>t<<64-s|e>>>s-32,rotrBL:(t,e,s)=>t>>>s-32|e<<64-s,rotr32H:(t,e)=>e,rotr32L:(t,e)=>t,rotlSH:(t,e,s)=>t<<s|e>>>32-s,rotlSL:(t,e,s)=>e<<s|t>>>32-s,rotlBH:(t,e,s)=>e<<s-32|t>>>64-s,rotlBL:(t,e,s)=>t<<s-32|e>>>64-s,add:function(t,e,s,h){const i=(e>>>0)+(h>>>0);return{h:t+s+(i/2**32|0)|0,l:0|i}},add3L:(t,e,s)=>(t>>>0)+(e>>>0)+(s>>>0),add3H:(t,e,s,h)=>e+s+h+(t/2**32|0)|0,add4L:(t,e,s,h)=>(t>>>0)+(e>>>0)+(s>>>0)+(h>>>0),add4H:(t,e,s,h,i)=>e+s+h+i+(t/2**32|0)|0,add5H:(t,e,s,h,i,r)=>e+s+h+i+r+(t/2**32|0)|0,add5L:(t,e,s,h,i)=>(t>>>0)+(e>>>0)+(s>>>0)+(h>>>0)+(i>>>0)},[l,b]=d.split(["0x428a2f98d728ae22","0x7137449123ef65cd","0xb5c0fbcfec4d3b2f","0xe9b5dba58189dbbc","0x3956c25bf348b538","0x59f111f1b605d019","0x923f82a4af194f9b","0xab1c5ed5da6d8118","0xd807aa98a3030242","0x12835b0145706fbe","0x243185be4ee4b28c","0x550c7dc3d5ffb4e2","0x72be5d74f27b896f","0x80deb1fe3b1696b1","0x9bdc06a725c71235","0xc19bf174cf692694","0xe49b69c19ef14ad2","0xefbe4786384f25e3","0x0fc19dc68b8cd5b5","0x240ca1cc77ac9c65","0x2de92c6f592b0275","0x4a7484aa6ea6e483","0x5cb0a9dcbd41fbd4","0x76f988da831153b5","0x983e5152ee66dfab","0xa831c66d2db43210","0xb00327c898fb213f","0xbf597fc7beef0ee4","0xc6e00bf33da88fc2","0xd5a79147930aa725","0x06ca6351e003826f","0x142929670a0e6e70","0x27b70a8546d22ffc","0x2e1b21385c26c926","0x4d2c6dfc5ac42aed","0x53380d139d95b3df","0x650a73548baf63de","0x766a0abb3c77b2a8","0x81c2c92e47edaee6","0x92722c851482353b","0xa2bfe8a14cf10364","0xa81a664bbc423001","0xc24b8b70d0f89791","0xc76c51a30654be30","0xd192e819d6ef5218","0xd69906245565a910","0xf40e35855771202a","0x106aa07032bbd1b8","0x19a4c116b8d2d0c8","0x1e376c085141ab53","0x2748774cdf8eeb99","0x34b0bcb5e19b48a8","0x391c0cb3c5c95a63","0x4ed8aa4ae3418acb","0x5b9cca4f7763e373","0x682e6ff3d6b2b8a3","0x748f82ee5defb2fc","0x78a5636f43172f60","0x84c87814a1f0ab72","0x8cc702081a6439ec","0x90befffa23631e28","0xa4506cebde82bde9","0xbef9a3f7b2c67915","0xc67178f2e372532b","0xca273eceea26619c","0xd186b8c721c0c207","0xeada7dd6cde0eb1e","0xf57d4f7fee6ed178","0x06f067aa72176fba","0x0a637dc5a2c898a6","0x113f9804bef90dae","0x1b710b35131c471b","0x28db77f523047d84","0x32caab7b40c72493","0x3c9ebe0a15c9bebc","0x431d67c49c100d4c","0x4cc5d4becb3e42b6","0x597f299cfc657e2a","0x5fcb6fab3ad6faec","0x6c44198c4a475817"].map((t=>BigInt(t)))),u=new Uint32Array(80),x=new Uint32Array(80);class p extends o{constructor(){super(128,64,16,!1),this.Ah=1779033703,this.Al=-205731576,this.Bh=-1150833019,this.Bl=-2067093701,this.Ch=1013904242,this.Cl=-23791573,this.Dh=-1521486534,this.Dl=1595750129,this.Eh=1359893119,this.El=-1377402159,this.Fh=-1694144372,this.Fl=725511199,this.Gh=528734635,this.Gl=-79577749,this.Hh=1541459225,this.Hl=327033209}get(){const{Ah:t,Al:e,Bh:s,Bl:h,Ch:i,Cl:r,Dh:n,Dl:o,Eh:c,El:a,Fh:f,Fl:d,Gh:l,Gl:b,Hh:u,Hl:x}=this;return[t,e,s,h,i,r,n,o,c,a,f,d,l,b,u,x]}set(t,e,s,h,i,r,n,o,c,a,f,d,l,b,u,x){this.Ah=0|t,this.Al=0|e,this.Bh=0|s,this.Bl=0|h,this.Ch=0|i,this.Cl=0|r,this.Dh=0|n,this.Dl=0|o,this.Eh=0|c,this.El=0|a,this.Fh=0|f,this.Fl=0|d,this.Gh=0|l,this.Gl=0|b,this.Hh=0|u,this.Hl=0|x}process(t,e){for(let s=0;s<16;s++,e+=4)u[s]=t.getUint32(e),x[s]=t.getUint32(e+=4);for(let t=16;t<80;t++){const e=0|u[t-15],s=0|x[t-15],h=d.rotrSH(e,s,1)^d.rotrSH(e,s,8)^d.shrSH(e,s,7),i=d.rotrSL(e,s,1)^d.rotrSL(e,s,8)^d.shrSL(e,s,7),r=0|u[t-2],n=0|x[t-2],o=d.rotrSH(r,n,19)^d.rotrBH(r,n,61)^d.shrSH(r,n,6),c=d.rotrSL(r,n,19)^d.rotrBL(r,n,61)^d.shrSL(r,n,6),a=d.add4L(i,c,x[t-7],x[t-16]),f=d.add4H(a,h,o,u[t-7],u[t-16]);u[t]=0|f,x[t]=0|a}let{Ah:s,Al:h,Bh:i,Bl:r,Ch:n,Cl:o,Dh:c,Dl:a,Eh:f,El:p,Fh:g,Fl:w,Gh:L,Gl:H,Hh:y,Hl:B}=this;for(let t=0;t<80;t++){const e=d.rotrSH(f,p,14)^d.rotrSH(f,p,18)^d.rotrBH(f,p,41),E=d.rotrSL(f,p,14)^d.rotrSL(f,p,18)^d.rotrBL(f,p,41),A=f&g^~f&L,S=p&w^~p&H,C=d.add5L(B,E,S,b[t],x[t]),U=d.add5H(C,y,e,A,l[t],u[t]),D=0|C,F=d.rotrSH(s,h,28)^d.rotrBH(s,h,34)^d.rotrBH(s,h,39),G=d.rotrSL(s,h,28)^d.rotrBL(s,h,34)^d.rotrBL(s,h,39),m=s&i^s&n^i&n,I=h&r^h&o^r&o;y=0|L,B=0|H,L=0|g,H=0|w,g=0|f,w=0|p,({h:f,l:p}=d.add(0|c,0|a,0|U,0|D)),c=0|n,a=0|o,n=0|i,o=0|r,i=0|s,r=0|h;const N=d.add3L(D,G,I);s=d.add3H(N,U,F,m),h=0|N}({h:s,l:h}=d.add(0|this.Ah,0|this.Al,0|s,0|h)),({h:i,l:r}=d.add(0|this.Bh,0|this.Bl,0|i,0|r)),({h:n,l:o}=d.add(0|this.Ch,0|this.Cl,0|n,0|o)),({h:c,l:a}=d.add(0|this.Dh,0|this.Dl,0|c,0|a)),({h:f,l:p}=d.add(0|this.Eh,0|this.El,0|f,0|p)),({h:g,l:w}=d.add(0|this.Fh,0|this.Fl,0|g,0|w)),({h:L,l:H}=d.add(0|this.Gh,0|this.Gl,0|L,0|H)),({h:y,l:B}=d.add(0|this.Hh,0|this.Hl,0|y,0|B)),this.set(s,h,i,r,n,o,c,a,f,p,g,w,L,H,y,B)}roundClean(){u.fill(0),x.fill(0)}destroy(){this.buffer.fill(0),this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)}}class g extends p{constructor(){super(),this.Ah=-1942145080,this.Al=424955298,this.Bh=1944164710,this.Bl=-1982016298,this.Ch=502970286,this.Cl=855612546,this.Dh=1738396948,this.Dl=1479516111,this.Eh=258812777,this.El=2077511080,this.Fh=2011393907,this.Fl=79989058,this.Gh=1067287976,this.Gl=1780299464,this.Hh=286451373,this.Hl=-1848208735,this.outputLen=28}}class w extends p{constructor(){super(),this.Ah=573645204,this.Al=-64227540,this.Bh=-1621794909,this.Bl=-934517566,this.Ch=596883563,this.Cl=1867755857,this.Dh=-1774684391,this.Dl=1497426621,this.Eh=-1775747358,this.El=-1467023389,this.Fh=-1101128155,this.Fl=1401305490,this.Gh=721525244,this.Gl=746961066,this.Hh=246885852,this.Hl=-2117784414,this.outputLen=32}}class L extends p{constructor(){super(),this.Ah=-876896931,this.Al=-1056596264,this.Bh=1654270250,this.Bl=914150663,this.Ch=-1856437926,this.Cl=812702999,this.Dh=355462360,this.Dl=-150054599,this.Eh=1731405415,this.El=-4191439,this.Fh=-1900787065,this.Fl=1750603025,this.Gh=-619958771,this.Gl=1694076839,this.Hh=1203062813,this.Hl=-1090891868,this.outputLen=48}}const H=n((()=>new p)),y=n((()=>new g)),B=n((()=>new w)),E=n((()=>new L));export{p as SHA512,E as sha384,H as sha512,y as sha512_224,B as sha512_256};export default null;
8//# sourceMappingURL=/sm/25ef7ec32d52ab376d05edb8d663f6f9885235f7c4d8ebc8cb0aab306fd143bb.map