Compare commits
	
		
			2 Commits
		
	
	
		
			master
			...
			feature/no
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 011386fb8d | |||
| 4d77f5d38c | 
| @ -1,8 +1,14 @@ | ||||
| import { Controller } from "@hotwired/stimulus" | ||||
| import { Nostrify } from "nostrify" | ||||
| 
 | ||||
| // Connects to data-controller="settings--nostr-pubkey"
 | ||||
| export default class extends Controller { | ||||
|   static targets = [ "noExtension", "setPubkey", "pubkeyBech32Input" ] | ||||
|   static targets = [ | ||||
|     "noExtension", | ||||
|     "setPubkey", "pubkeyBech32Input", | ||||
|     "relayList", "relayListStatus", | ||||
|     "profileStatusNip05", "profileStatusLud16" | ||||
|   ] | ||||
|   static values  = { | ||||
|     userAddress: String, | ||||
|     pubkeyHex: String, | ||||
| @ -15,6 +21,14 @@ export default class extends Controller { | ||||
|       if (this.hasSetPubkeyTarget) { | ||||
|         this.setPubkeyTarget.disabled = false | ||||
|       } | ||||
| 
 | ||||
|       if (this.pubkeyHexValue) { | ||||
|         this.discoverUserOnNostr().then(() => { | ||||
|           this.renderRelayStatus() | ||||
|           this.renderProfileNip05Status() | ||||
|           this.renderProfileLud16Status() | ||||
|         }) | ||||
|       } | ||||
|     } else { | ||||
|       this.noExtensionTarget.classList.remove("hidden") | ||||
|     } | ||||
| @ -49,8 +63,172 @@ export default class extends Controller { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   async discoverUserOnNostr () { | ||||
|     this.nip65Relays = await this.findUserRelays() | ||||
|     this.profile = await this.findUserProfile() | ||||
|   } | ||||
| 
 | ||||
|   async findUserRelays () { | ||||
|     const controller = new AbortController(); | ||||
|     const signal = controller.signal; | ||||
|     const filters = [{ kinds: [10002], authors: [this.pubkeyHexValue], limit: 1 }] | ||||
|     const messages = [] | ||||
| 
 | ||||
|     for await (const msg of this.discoveryPool.req(filters, { signal })) { | ||||
|       if (msg[0] === 'EVENT') { | ||||
|         if (!messages.find(m => m.id === msg[2].id)) { | ||||
|           messages.push(msg[2]) | ||||
|         } | ||||
|       } | ||||
|       if (msg[0] === 'EOSE') { break } | ||||
|     } | ||||
| 
 | ||||
|     // Close the relay subscription
 | ||||
|     controller.abort() | ||||
|     if (messages.length === 0) { return messages } | ||||
| 
 | ||||
|     const sortedMessages = messages.sort((a, b) => a.createdAt - b.createdAt) | ||||
|     const newestMessage = messages[messages.length - 1] | ||||
| 
 | ||||
|     return newestMessage.tags.filter(t => t[0] === 'r') | ||||
|                              .map(t => { return { url: t[1], marker: t[2] } }) | ||||
|   } | ||||
| 
 | ||||
|   async findUserProfile () { | ||||
|     const controller = new AbortController(); | ||||
|     const signal = controller.signal; | ||||
|     const filters = [{ kinds: [0], authors: [this.pubkeyHexValue], limit: 1 }] | ||||
|     const messages = [] | ||||
| 
 | ||||
|     for await (const msg of this.discoveryPool.req(filters, { signal })) { | ||||
|       if (msg[0] === 'EVENT') { | ||||
|         if (!messages.find(m => m.id === msg[2].id)) { | ||||
|           messages.push(msg[2]) | ||||
|         } | ||||
|       } | ||||
|       if (msg[0] === 'EOSE') { break } | ||||
|     } | ||||
| 
 | ||||
|     // Close the relay subscription
 | ||||
|     controller.abort() | ||||
|     if (messages.length === 0) { return null } | ||||
| 
 | ||||
|     const sortedMessages = messages.sort((a, b) => a.createdAt - b.createdAt) | ||||
|     const newestMessage = messages[messages.length - 1] | ||||
| 
 | ||||
|     return JSON.parse(newestMessage.content) | ||||
|   } | ||||
| 
 | ||||
|   renderRelayStatus () { | ||||
|     let showStatus | ||||
| 
 | ||||
|     if (this.nip65Relays.length > 0) { | ||||
|       if (this.relaysContainAccountsRelay) { | ||||
|         showStatus = 'green' | ||||
|       } else { | ||||
|         showStatus = 'orange' | ||||
|       } | ||||
|     } else { | ||||
|       showStatus = 'red' | ||||
|     } | ||||
|     // showStatus = 'red'
 | ||||
| 
 | ||||
|     this.relayListStatusTarget | ||||
|       .querySelector(`.status-${showStatus}`) | ||||
|       .classList.remove("hidden") | ||||
|   } | ||||
| 
 | ||||
|   renderProfileNip05Status () { | ||||
|     let showStatus | ||||
| 
 | ||||
|     if (this.profile?.nip05) { | ||||
|       if (this.profile.nip05 === this.userAddressValue) { | ||||
|         showStatus = 'green' | ||||
|       } else { | ||||
|         showStatus = 'red' | ||||
|       } | ||||
|     } else { | ||||
|       showStatus = 'orange' | ||||
|     } | ||||
| 
 | ||||
|     this.profileStatusNip05Target | ||||
|       .querySelector(`.status-${showStatus}`) | ||||
|       .classList.remove("hidden") | ||||
|   } | ||||
| 
 | ||||
|   renderProfileLud16Status () { | ||||
|     let showStatus | ||||
| 
 | ||||
|     if (this.profile?.lud16) { | ||||
|       if (this.profile.lud16 === this.userAddressValue) { | ||||
|         showStatus = 'green' | ||||
|       } else { | ||||
|         showStatus = 'red' | ||||
|       } | ||||
|     } else { | ||||
|       showStatus = 'orange' | ||||
|     } | ||||
| 
 | ||||
|     this.profileStatusLud16Target | ||||
|       .querySelector(`.status-${showStatus}`) | ||||
|       .classList.remove("hidden") | ||||
|   } | ||||
| 
 | ||||
|   // renderRelayList (relays) {
 | ||||
|   //   const html = relays.map(relay => `
 | ||||
|   //     <li class="flex items-center justify-between p-2 border-b">
 | ||||
|   //       <span>${relay.url}</span>
 | ||||
|   //       <button 
 | ||||
|   //         data-action="click->list#handleItemClick" 
 | ||||
|   //         data-item="${relay.url}"
 | ||||
|   //         class="bg-blue-500 text-white px-3 py-1 rounded">
 | ||||
|   //         Action
 | ||||
|   //       </button>
 | ||||
|   //     </li>
 | ||||
|   //   `).join("")
 | ||||
|   //
 | ||||
|   //   this.relayListTarget.innerHTML = html
 | ||||
|   // }
 | ||||
| 
 | ||||
|   get csrfToken () { | ||||
|     const element = document.head.querySelector('meta[name="csrf-token"]') | ||||
|     return element.getAttribute("content") | ||||
|   } | ||||
| 
 | ||||
|   // Used to find a user's profile and relays
 | ||||
|   get discoveryRelays () { | ||||
|     return [ | ||||
|       'ws://localhost:4777', | ||||
|       'wss://nostr.kosmos.org', | ||||
|       'wss://purplepag.es', | ||||
|       // 'wss://relay.nostr.band',
 | ||||
|       // 'wss://njump.me',
 | ||||
|       // 'wss://relay.damus.io',
 | ||||
|       // 'wss://nos.lol',
 | ||||
|       // 'wss://eden.nostr.land',
 | ||||
|       // 'wss://relay.snort.social',
 | ||||
|       // 'wss://nostr.wine',
 | ||||
|       // 'wss://relay.primal.net',
 | ||||
|       // 'wss://nostr.bitcoiner.social',
 | ||||
|     ] | ||||
|   } | ||||
| 
 | ||||
|   get discoveryPool () { | ||||
|     if (!this._discoveryPool) { | ||||
|       this._discoveryPool = new Nostrify.NPool({ | ||||
|         open: (url) => new Nostrify.NRelay1(url), | ||||
|         reqRouter: async (filters) => new Map( | ||||
|           this.discoveryRelays.map(relayUrl => [ relayUrl, filters ]) | ||||
|         ), | ||||
|         eventRouter: async (event) => [], | ||||
|       }) | ||||
|     } | ||||
| 
 | ||||
|     return this._discoveryPool | ||||
|   } | ||||
| 
 | ||||
|   get relaysContainAccountsRelay () { | ||||
|     // TODO use URL from view/settings
 | ||||
|     return !!this.nip65Relays.find(r => r.url.match('wss://nostr.kosmos.org')) | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -1,46 +1,32 @@ | ||||
| <section> | ||||
|   <h3>Nostr</h3> | ||||
|   <h4 class="mb-0">Public Key</h4> | ||||
|   <div data-controller="settings--nostr-pubkey" | ||||
|        data-settings--nostr-pubkey-user-address-value="<%= current_user.address %>" | ||||
|        data-settings--nostr-pubkey-site-value="<%= Setting.accounts_domain %>" | ||||
|        data-settings--nostr-pubkey-shared-secret-value="<%= session[:shared_secret] %>" | ||||
|        data-settings--nostr-pubkey-pubkey-hex-value="<%= current_user.nostr_pubkey %>"> | ||||
| 
 | ||||
|     <p class="<%= current_user.nostr_pubkey.present? ? '' : 'hidden' %> mt-2 flex gap-1"> | ||||
| <div data-controller="settings--nostr-pubkey" | ||||
|      data-settings--nostr-pubkey-user-address-value="<%= current_user.address %>" | ||||
|      data-settings--nostr-pubkey-site-value="<%= Setting.accounts_domain %>" | ||||
|      data-settings--nostr-pubkey-shared-secret-value="<%= session[:shared_secret] %>" | ||||
|      data-settings--nostr-pubkey-pubkey-hex-value="<%= current_user.nostr_pubkey %>"> | ||||
|   <section> | ||||
|     <h3>Nostr</h3> | ||||
|     <h4 class="mb-0"> | ||||
|       Public Key | ||||
|     </h4> | ||||
|     <p class="<%= current_user.nostr_pubkey.present? ? '' : 'hidden' %> mt-2 flex gap-x-1"> | ||||
|       <input type="text" value="<%= current_user.nostr_pubkey_bech32 %>" disabled | ||||
|              data-settings--nostr-pubkey-target="pubkeyBech32Input" | ||||
|              name="nostr_public_key" class="relative grow" /> | ||||
|              name="nostr_public_key" class="w-full" /> | ||||
|       <%= link_to nostr_pubkey_settings_path, | ||||
|             class: 'btn-md btn-outline text-red-700 relative shrink-0', | ||||
|             class: 'btn-md btn-outline relative grow-0 shrink-0 text-red-700', | ||||
|             data: { turbo_method: :delete, turbo_confirm: 'Are you sure?' } do %> | ||||
|         Remove | ||||
|       <% end %> | ||||
|     </p> | ||||
| 
 | ||||
|     <% if current_user.nostr_pubkey.present? %> | ||||
|     <div class="rounded-md bg-blue-50 p-4"> | ||||
|       <div class="flex"> | ||||
|         <div class="flex-shrink-0"> | ||||
|           <svg class="h-5 w-5 text-blue-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"> | ||||
|             <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z" clip-rule="evenodd" /> | ||||
|           </svg> | ||||
|         </div> | ||||
|         <div class="ml-3 flex-1"> | ||||
|           <p class="text-sm text-blue-800"> | ||||
|             Your user address <strong><%= current_user.address %></strong> is | ||||
|             also a Nostr address now. Use your favorite Nostr app, or for | ||||
|             example <a href="http://metadata.nostr.com" target="_blank" | ||||
|               class="underline">metadata.nostr.com</a>, to add this | ||||
|             <strong>NIP-05</strong> address to your public profile. | ||||
|           </p> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <!-- <div> --> | ||||
|     <!--   Pubkey present --> | ||||
|     <!-- </div> --> | ||||
|     <% else %> | ||||
|     <p class="my-4"> | ||||
|       If you use any apps on the Nostr network, you can verify your public key | ||||
|       with us in order to enable Nostr-specific features for your account. | ||||
|       Verify your Nostr public key with us in order to enable Nostr-specific | ||||
|       features for your account. | ||||
|     </p> | ||||
|     <% end %> | ||||
| 
 | ||||
| @ -58,8 +44,8 @@ | ||||
|           </h3> | ||||
|           <div class="mt-2 mb-0 text-sm text-blue-800"> | ||||
|             <p> | ||||
|               We recommend Alby, which you can also use for your Lightning | ||||
|               Wallet. | ||||
|               We recommend Alby, which you can also use a wallet for your | ||||
|               Lightning account. | ||||
|             </p> | ||||
|           </div> | ||||
|           <div class="mt-4"> | ||||
| @ -86,5 +72,113 @@ | ||||
|       </button> | ||||
|     </p> | ||||
|     <% end %> | ||||
|   </div> | ||||
| </section> | ||||
|   </section> | ||||
| 
 | ||||
|   <% if current_user.nostr_pubkey.present? %> | ||||
|     <section> | ||||
|       <h3>Profile</h3> | ||||
|       <div data-settings--nostr-pubkey-target="profileStatus" class="mb-4"> | ||||
|         <p class="status-green hidden flex gap-x-4 items-center"> | ||||
|           <span class="inline-block h-6 w-6 grow-0 text-emerald-500 %>"> | ||||
|             <%= render "icons/check-circle" %> | ||||
|           </span> | ||||
|           <span> | ||||
|             You already have a profile for your public key | ||||
|           </span> | ||||
|         </p> | ||||
|         <p class="status-orange hidden flex gap-x-4 items-center"> | ||||
|           <span class="inline-block h-6 w-6 grow-0 text-amber-500 %>"> | ||||
|             <%= render "icons/alert-octagon" %> | ||||
|           </span> | ||||
|           <span> | ||||
|             <strong><%= current_user.address %></strong> is not set as your Nostr address | ||||
|           </span> | ||||
|         </p> | ||||
|       </div> | ||||
|       <div data-settings--nostr-pubkey-target="profileStatusNip05" class="mb-4"> | ||||
|         <p class="status-green hidden flex gap-x-4 items-center"> | ||||
|           <span class="inline-block h-6 w-6 grow-0 text-emerald-500 %>"> | ||||
|             <%= render "icons/check-circle" %> | ||||
|           </span> | ||||
|           <span> | ||||
|             <strong><%= current_user.address %></strong> is set as your Nostr address | ||||
|           </span> | ||||
|         </p> | ||||
|         <p class="status-orange hidden flex gap-x-4 items-center"> | ||||
|           <span class="inline-block h-6 w-6 grow-0 text-amber-500 %>"> | ||||
|             <%= render "icons/alert-octagon" %> | ||||
|           </span> | ||||
|           <span> | ||||
|             <strong><%= current_user.address %></strong> is not set as your Nostr address | ||||
|           </span> | ||||
|         </p> | ||||
|         <p class="status-red hidden flex gap-x-4 items-center"> | ||||
|           <span class="inline-block h-6 w-6 grow-0 text-amber-500 %>"> | ||||
|             <%= render "icons/alert-octagon" %> | ||||
|           </span> | ||||
|           <span> | ||||
|             Your profile's Nostr address is not set to <strong><%= current_user.address %></strong> yet | ||||
|           </span> | ||||
|         </p> | ||||
|       </div> | ||||
|       <div data-settings--nostr-pubkey-target="profileStatusLud16"> | ||||
|         <p class="status-green hidden flex gap-x-4 items-center"> | ||||
|           <span class="inline-block h-6 w-6 grow-0 text-emerald-500 %>"> | ||||
|             <%= render "icons/check-circle" %> | ||||
|           </span> | ||||
|           <span> | ||||
|             <strong><%= current_user.address %></strong> is set as your Lightning address | ||||
|           </span> | ||||
|         </p> | ||||
|         <p class="status-orange hidden flex gap-x-4 items-center"> | ||||
|           <span class="inline-block h-6 w-6 grow-0 text-amber-500 %>"> | ||||
|             <%= render "icons/alert-octagon" %> | ||||
|           </span> | ||||
|           <span> | ||||
|             <strong><%= current_user.address %></strong> is not set as your Lightning address yet | ||||
|           </span> | ||||
|         </p> | ||||
|         <p class="status-red hidden flex gap-x-4 items-center"> | ||||
|           <span class="inline-block h-6 w-6 grow-0 text-amber-500 %>"> | ||||
|             <%= render "icons/alert-octagon" %> | ||||
|           </span> | ||||
|           <span> | ||||
|             Your profile's Lightning address is not set to <strong><%= current_user.address %></strong> yet | ||||
|           </span> | ||||
|         </p> | ||||
|       </div> | ||||
|     </section> | ||||
| 
 | ||||
|     <section> | ||||
|       <h3>Relays</h3> | ||||
|       <div data-settings--nostr-pubkey-target="relayListStatus"> | ||||
|         <p class="status-green hidden flex gap-x-4 items-center"> | ||||
|           <span class="inline-block h-6 w-6 grow-0 text-emerald-500 %>"> | ||||
|             <%= render "icons/check-circle" %> | ||||
|           </span> | ||||
|           <span> | ||||
|             You have a relay list, and the Kosmos relay is part of it | ||||
|           </span> | ||||
|         </p> | ||||
|         <p class="status-orange hidden flex gap-x-4 items-center"> | ||||
|           <span class="inline-block h-6 w-6 grow-0 text-amber-500 %>"> | ||||
|             <%= render "icons/alert-octagon" %> | ||||
|           </span> | ||||
|           <span> | ||||
|             The Kosmos relay is missing from your relay list | ||||
|           </span> | ||||
|         </p> | ||||
|         <p class="status-red hidden flex gap-x-4 items-center"> | ||||
|           <span class="inline-block h-6 w-6 grow-0 text-amber-500 %>"> | ||||
|             <%= render "icons/alert-octagon" %> | ||||
|           </span> | ||||
|           <span> | ||||
|             We could not find a relay list for your public key | ||||
|           </span> | ||||
|         </p> | ||||
|       </div> | ||||
|       <ul data-settings--nostr-pubkey-target="relayList"> | ||||
|       </ul> | ||||
|     </section> | ||||
|   <% end %> | ||||
| </div> | ||||
|  | ||||
| @ -6,3 +6,4 @@ pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true | ||||
| pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true | ||||
| pin_all_from "app/javascript/controllers", under: "controllers" | ||||
| pin "tailwindcss-stimulus-components" # @4.0.3 | ||||
| pin "nostrify" | ||||
|  | ||||
							
								
								
									
										11690
									
								
								vendor/javascript/nostrify.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11690
									
								
								vendor/javascript/nostrify.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1
									
								
								vendor/javascript/nostrify.js.map
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/javascript/nostrify.js.map
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user