diff --git a/README.md b/README.md index 1839351..daa0daf 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,13 @@ + + + + LNbits + + + +[![License: MIT](https://img.shields.io/badge/License-MIT-success?logo=open-source-initiative&logoColor=white)](./LICENSE) +[![Built for LNbits](https://img.shields.io/badge/Built%20for-LNbits-4D4DFF?logo=lightning&logoColor=white)](https://github.com/lnbits/lnbits) + # Nostr Market ([NIP-15](https://github.com/nostr-protocol/nips/blob/master/15.md)) - [LNbits](https://github.com/lnbits/lnbits) extension For more about LNBits extension check [this tutorial](https://github.com/lnbits/lnbits/wiki/LNbits-Extensions). @@ -147,3 +157,10 @@ Stall and product are _Parameterized Replaceable Events_ according to [NIP-33](h Order placing, invoicing, payment details and order statuses are handled over Nostr using [NIP-04](https://github.com/nostr-protocol/nips/blob/master/04.md). Customer support is handled over whatever communication method was specified. If communicationg via nostr, [NIP-04](https://github.com/nostr-protocol/nips/blob/master/04.md) is used. + +## Powered by LNbits + +[LNbits](https://lnbits.com) is a free and open-source lightning accounts system. + +[![Visit LNbits Shop](https://img.shields.io/badge/Visit-LNbits%20Shop-7C3AED?logo=shopping-cart&logoColor=white&labelColor=5B21B6)](https://shop.lnbits.com/) +[![Try myLNbits SaaS](https://img.shields.io/badge/Try-myLNbits%20SaaS-2563EB?logo=lightning&logoColor=white&labelColor=1E40AF)](https://my.lnbits.com/login) diff --git a/config.json b/config.json index 1aa34a8..3a670de 100644 --- a/config.json +++ b/config.json @@ -1,12 +1,15 @@ { - "name": "Nostr Market", + "id": "nostrmarket", "version": "1.1.0", + "name": "Nostr Market", + "repo": "https://github.com/lnbits/nostrmarket", "short_description": "Nostr Webshop/market on LNbits", - "tile": "/nostrmarket/static/images/nostr-market.png", + "description": "", + "tile": "/nostrmarket/static/images/bitcoin-shop.png", "min_lnbits_version": "1.4.0", "contributors": [ { - "name": "motorina0", + "name": "Vlad Stan", "uri": "https://github.com/motorina0", "role": "Contributor" }, @@ -19,6 +22,11 @@ "name": "talvasconcelos", "uri": "https://github.com/talvasconcelos", "role": "Developer" + }, + { + "name": "BenGWeeks", + "uri": "https://github.com/BenGWeeks", + "role": "Developer" } ], "images": [ @@ -44,5 +52,9 @@ ], "description_md": "https://raw.githubusercontent.com/lnbits/nostrmarket/main/description.md", "terms_and_conditions_md": "https://raw.githubusercontent.com/lnbits/nostrmarket/main/toc.md", - "license": "MIT" + "license": "MIT", + "paid_features": "", + "tags": ["Nostr", "Marketplace"], + "donate": "", + "hidden": false } diff --git a/description.md b/description.md index dfa898f..b4fc5d2 100644 --- a/description.md +++ b/description.md @@ -1,12 +1,10 @@ -> IMPORTANT: Nostr market needs the nostr-client extension installed. +Buy and sell products over Nostr using the NIP-15 marketplace protocol. -Buy and sell things over Nostr, using NIP15 https://github.com/nostr-protocol/nips/blob/master/15.md +Its functions include: -Nostr was partly based on the the previous version of this extension "Diagon Alley", so lends itself very well to buying and sellinng over Nostr. +- Managing products, sales, and customer communication as a merchant +- Browsing and ordering products as a customer +- Tracking order status and delivery +- Communicating via NIP-17 private direct messages (NIP-44 encryption + NIP-59 gift wrapping) -The Nostr Market extension includes: - -- A merchant client to manage products, sales and communication with customers. -- A customer client to find and order products from merchants, communicate with merchants and track status of ordered products. - -All communication happens over NIP-17 private direct messages (NIP-44 encryption + NIP-59 gift wrapping). +A decentralized commerce solution for merchants and buyers who want to trade goods and services over Nostr with end-to-end encrypted communication. diff --git a/static/components/merchant-tab.js b/static/components/merchant-tab.js index 8e9588c..d993bd4 100644 --- a/static/components/merchant-tab.js +++ b/static/components/merchant-tab.js @@ -29,7 +29,13 @@ window.app.component('merchant-tab', { }, computed: { marketClientUrl: function () { - return '/nostrmarket/market' + if (!this.publicKey) { + return '/nostrmarket/market' + } + + const url = new URL('/nostrmarket/market', window.location.origin) + url.searchParams.set('merchant', this.publicKey) + return url.pathname + url.search } }, methods: { diff --git a/static/market/js/utils.js b/static/market/js/utils.js index 2e41b49..8a3a98b 100644 --- a/static/market/js/utils.js +++ b/static/market/js/utils.js @@ -1,5 +1,43 @@ var NostrTools = window.NostrTools +;(function ensureRandomUUID() { + if (!globalThis.crypto) { + globalThis.crypto = {} + } + if (!globalThis.crypto.randomUUID) { + globalThis.crypto.randomUUID = function () { + const getRandomValues = globalThis.crypto.getRandomValues + if (getRandomValues) { + const bytes = new Uint8Array(16) + getRandomValues.call(globalThis.crypto, bytes) + bytes[6] = (bytes[6] & 0x0f) | 0x40 + bytes[8] = (bytes[8] & 0x3f) | 0x80 + const hex = Array.from(bytes, b => + b.toString(16).padStart(2, '0') + ).join('') + return ( + hex.slice(0, 8) + + '-' + + hex.slice(8, 12) + + '-' + + hex.slice(12, 16) + + '-' + + hex.slice(16, 20) + + '-' + + hex.slice(20) + ) + } + + let d = Date.now() + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { + const r = (d + Math.random() * 16) % 16 | 0 + d = Math.floor(d / 16) + return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16) + }) + } + } +})() + var defaultRelays = [ 'wss://relay.damus.io', 'wss://relay.snort.social', @@ -44,13 +82,24 @@ function confirm(message) { async function hash(string) { - const utf8 = new TextEncoder().encode(string) - const hashBuffer = await crypto.subtle.digest('SHA-256', utf8) - const hashArray = Array.from(new Uint8Array(hashBuffer)) - const hashHex = hashArray - .map(bytes => bytes.toString(16).padStart(2, '0')) - .join('') - return hashHex + const subtle = globalThis.crypto && globalThis.crypto.subtle + if (subtle && subtle.digest) { + const utf8 = new TextEncoder().encode(string) + const hashBuffer = await subtle.digest('SHA-256', utf8) + const hashArray = Array.from(new Uint8Array(hashBuffer)) + return hashArray.map(bytes => bytes.toString(16).padStart(2, '0')).join('') + } + + // Fallback for non-secure contexts where crypto.subtle is unavailable. + return fallbackHash(string) +} + +function fallbackHash(string) { + let hash = 5381 + for (let i = 0; i < string.length; i++) { + hash = ((hash << 5) + hash) + string.charCodeAt(i) + } + return (hash >>> 0).toString(16).padStart(8, '0') } function isJson(str) { diff --git a/templates/nostrmarket/components/merchant-tab.html b/templates/nostrmarket/components/merchant-tab.html index 5d41ab2..497478a 100644 --- a/templates/nostrmarket/components/merchant-tab.html +++ b/templates/nostrmarket/components/merchant-tab.html @@ -9,29 +9,26 @@
- Edit - - Show Keys - + + + + + + View Keys + Show public/private keys + + + Saved Profiles @@ -69,6 +66,13 @@ + +