WIP Verify and respond to zap requests
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is passing
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			This commit is contained in:
		
							parent
							
								
									77e2fe5792
								
							
						
					
					
						commit
						c3b82fc2a9
					
				| @ -43,7 +43,7 @@ class LnurlpayController < ApplicationController | |||||||
| 
 | 
 | ||||||
|   # GET /lnurlpay/:username/invoice |   # GET /lnurlpay/:username/invoice | ||||||
|   def invoice |   def invoice | ||||||
|     amount = params[:amount].to_i / 1000 # msats |     amount = params[:amount].to_i / 1000 # msats to sats | ||||||
|     comment = params[:comment] || "" |     comment = params[:comment] || "" | ||||||
|     address = @user.address |     address = @user.address | ||||||
| 
 | 
 | ||||||
| @ -52,33 +52,19 @@ class LnurlpayController < ApplicationController | |||||||
|       return |       return | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     if !valid_comment?(comment) |     if params[:nostr].present? | ||||||
|       render json: { status: "ERROR", reason: "Comment too long" } |       handle_zap_request amount, params[:nostr], params[:lnurl] | ||||||
|       return |     else | ||||||
|  |       handle_pay_request address, amount, comment | ||||||
|     end |     end | ||||||
| 
 |  | ||||||
|     memo = "To #{address}" |  | ||||||
|     memo = "#{memo}: \"#{comment}\"" if comment.present? |  | ||||||
| 
 |  | ||||||
|     payment_request = @user.ln_create_invoice({ |  | ||||||
|       amount: amount, # we create invoices in sats |  | ||||||
|       memo: memo, |  | ||||||
|       description_hash: Digest::SHA2.hexdigest(metadata(address)), |  | ||||||
|     }) |  | ||||||
| 
 |  | ||||||
|     render json: { |  | ||||||
|       status: "OK", |  | ||||||
|       successAction: { |  | ||||||
|         tag: "message", |  | ||||||
|         message: "Sats received. Thank you!" |  | ||||||
|       }, |  | ||||||
|       routes: [], |  | ||||||
|       pr: payment_request |  | ||||||
|     } |  | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   private |   private | ||||||
| 
 | 
 | ||||||
|  |     def check_service_available | ||||||
|  |       http_status :not_found unless Setting.lndhub_enabled? | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|     def find_user |     def find_user | ||||||
|       @user = User.where(cn: params[:username], ou: Setting.primary_domain).first |       @user = User.where(cn: params[:username], ou: Setting.primary_domain).first | ||||||
|       http_status :not_found if @user.nil? |       http_status :not_found if @user.nil? | ||||||
| @ -88,6 +74,10 @@ class LnurlpayController < ApplicationController | |||||||
|       "[[\"text/identifier\", \"#{address}\"], [\"text/plain\", \"Send sats, receive thanks.\"]]" |       "[[\"text/identifier\", \"#{address}\"], [\"text/plain\", \"Send sats, receive thanks.\"]]" | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  |     def zap_metadata(event) | ||||||
|  |       "[[\"application/json\", #{event.to_json}]]" | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|     def valid_amount?(amount_in_sats) |     def valid_amount?(amount_in_sats) | ||||||
|       amount_in_sats <= MAX_SATS && amount_in_sats >= MIN_SATS |       amount_in_sats <= MAX_SATS && amount_in_sats >= MIN_SATS | ||||||
|     end |     end | ||||||
| @ -96,9 +86,63 @@ class LnurlpayController < ApplicationController | |||||||
|       comment.length <= MAX_COMMENT_CHARS |       comment.length <= MAX_COMMENT_CHARS | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     private |     def handle_pay_request(address, amount, comment) | ||||||
|  |       if !valid_comment?(comment) | ||||||
|  |         render json: { status: "ERROR", reason: "Comment too long" } | ||||||
|  |         return | ||||||
|  |       end | ||||||
| 
 | 
 | ||||||
|     def check_service_available |       memo = "To #{address}" | ||||||
|       http_status :not_found unless Setting.lndhub_enabled? |       memo = "#{memo}: \"#{comment}\"" if comment.present? | ||||||
|  | 
 | ||||||
|  |       payment_request = @user.ln_create_invoice({ | ||||||
|  |         amount: amount, # sats | ||||||
|  |         memo: memo, | ||||||
|  |         description_hash: Digest::SHA2.hexdigest(metadata(address)), | ||||||
|  |       }) | ||||||
|  | 
 | ||||||
|  |       render json: { | ||||||
|  |         status: "OK", | ||||||
|  |         successAction: { | ||||||
|  |           tag: "message", | ||||||
|  |           message: "Sats received. Thank you!" | ||||||
|  |         }, | ||||||
|  |         routes: [], | ||||||
|  |         pr: payment_request | ||||||
|  |       } | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     def nostr_event_from_payload(nostr_param) | ||||||
|  |       event_obj = JSON.parse(nostr_param).transform_keys(&:to_sym) | ||||||
|  |       Nostr::Event.new(**event_obj) | ||||||
|  |     rescue => e | ||||||
|  |       return nil | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     def valid_zap_request?(amount, event, lnurl) | ||||||
|  |       NostrManager::VerifyZapRequest.call( | ||||||
|  |         amount: amount, event: event, lnurl: lnurl | ||||||
|  |       ) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     def handle_zap_request(amount, nostr_param, lnurl_param) | ||||||
|  |       event = nostr_event_from_payload(nostr_param) | ||||||
|  | 
 | ||||||
|  |       unless event.present? && valid_zap_request?(amount*1000, event, lnurl_param) | ||||||
|  |         render json: { status: "ERROR", reason: "Invalid zap request" } | ||||||
|  |         return | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       # TODO | ||||||
|  |       # raise zap_metadata(event).inspect | ||||||
|  | 
 | ||||||
|  |       payment_request = @user.ln_create_invoice({ | ||||||
|  |         amount: amount, # sats | ||||||
|  |         # TODO should be npub instead of address? | ||||||
|  |         memo: "Zapped #{@user.address} on Nostr", # TODO include event ID if given | ||||||
|  |         description_hash: Digest::SHA2.hexdigest(zap_metadata(event)), | ||||||
|  |       }) | ||||||
|  | 
 | ||||||
|  |       render json: { status: "OK", pr: payment_request } | ||||||
|     end |     end | ||||||
| end | end | ||||||
|  | |||||||
							
								
								
									
										51
									
								
								app/services/nostr_manager/verify_zap_request.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								app/services/nostr_manager/verify_zap_request.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | |||||||
|  | module NostrManager | ||||||
|  |   class VerifyZapRequest < NostrManagerService | ||||||
|  |     def initialize(amount:, event:, lnurl: nil) | ||||||
|  |       @amount, @event, @lnurl = amount, event, lnurl | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     # https://github.com/nostr-protocol/nips/blob/27fef638e2460139cc9078427a0aec0ce4470517/57.md#appendix-d-lnurl-server-zap-request-validation | ||||||
|  |     def call | ||||||
|  |       tags = parse_tags(@event.tags) | ||||||
|  | 
 | ||||||
|  |       @event.verify_signature && | ||||||
|  |       @event.kind == 9734 && | ||||||
|  |       tags.present? && | ||||||
|  |       valid_p_tag?(tags[:p]) && | ||||||
|  |       valid_e_tag?(tags[:e]) && | ||||||
|  |       valid_a_tag?(tags[:a]) && | ||||||
|  |       valid_amount_tag?(tags[:amount]) && | ||||||
|  |       valid_lnurl_tag?(tags[:lnurl]) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     def valid_p_tag?(tag) | ||||||
|  |       return false unless tag.present? && tag.length == 1 | ||||||
|  |       key = Nostr::PublicKey.new(tag.first) rescue nil | ||||||
|  |       key.present? | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     def valid_e_tag?(tag) | ||||||
|  |       return true unless tag.present? | ||||||
|  |       # TODO validate format of event ID properly | ||||||
|  |       tag.length == 1 && tag.first.is_a?(String) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     def valid_a_tag?(tag) | ||||||
|  |       return true unless tag.present? | ||||||
|  |       # TODO validate format of event coordinate properly | ||||||
|  |       tag.length == 1 && tag.first.is_a?(String) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     def valid_amount_tag?(tag) | ||||||
|  |       return true unless tag.present? | ||||||
|  |       amount = tag.first | ||||||
|  |       amount.is_a?(String) && amount.to_i == @amount | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     def valid_lnurl_tag?(tag) | ||||||
|  |       return true unless tag.present? | ||||||
|  |       # TODO validate lnurl matching recipient's lnurlp | ||||||
|  |       tag.first.is_a?(String) | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										22
									
								
								spec/fixtures/nostr/zap_request_event.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								spec/fixtures/nostr/zap_request_event.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | { | ||||||
|  |   "kind": 9734, | ||||||
|  |   "created_at": 1712066899, | ||||||
|  |   "content": "", | ||||||
|  |   "tags": [ | ||||||
|  |     ["p", "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"], | ||||||
|  |     ["amount", "21000"], | ||||||
|  |     [ | ||||||
|  |       "relays", | ||||||
|  |       "wss://relay.primal.net", | ||||||
|  |       "wss://relay.snort.social", | ||||||
|  |       "wss://nostr.wine", | ||||||
|  |       "wss://relay.damus.io", | ||||||
|  |       "wss://eden.nostr.land", | ||||||
|  |       "wss://atlas.nostr.land", | ||||||
|  |       "wss://nostr.bitcoiner.social", | ||||||
|  |       "wss://relay.mostr.pub", | ||||||
|  |       "wss://relay.mostr.pub/", | ||||||
|  |       "wss://nostr-01.bolt.observer" | ||||||
|  |     ] | ||||||
|  |   ] | ||||||
|  | } | ||||||
| @ -1,9 +1,8 @@ | |||||||
| require 'rails_helper' | require 'rails_helper' | ||||||
| 
 | 
 | ||||||
| RSpec.describe "/lnurlpay", type: :request do | RSpec.describe "/lnurlpay", type: :request do | ||||||
| 
 |  | ||||||
|   context "Non-existent user" do |   context "Non-existent user" do | ||||||
|     describe "GET /.well-known/lnurlpay/:username" do |     describe "GET /.well-known/lnurlp/:username" do | ||||||
|       it "returns a 404" do |       it "returns a 404" do | ||||||
|         get lightning_address_path(username: "csw") |         get lightning_address_path(username: "csw") | ||||||
|         expect(response).to have_http_status(:not_found) |         expect(response).to have_http_status(:not_found) | ||||||
| @ -32,7 +31,7 @@ RSpec.describe "/lnurlpay", type: :request do | |||||||
|       login_as user, :scope => :user |       login_as user, :scope => :user | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     describe "GET /.well-known/lnurlpay/:username" do |     describe "GET /.well-known/lnurlp/:username" do | ||||||
|       it "returns a formatted Lightning Address response" do |       it "returns a formatted Lightning Address response" do | ||||||
|         get lightning_address_path(username: "satoshi") |         get lightning_address_path(username: "satoshi") | ||||||
| 
 | 
 | ||||||
| @ -67,29 +66,83 @@ RSpec.describe "/lnurlpay", type: :request do | |||||||
|         expect(res["pr"]).to eq("lnbc50u1p3lwgknpp52g78gqya5euvzjc53fc6hkmlm2rfjhcd305tcmc0g9gaestav48sdq4gdhkven9v5sx6mmwv4ujzcqzpgxqyz5vqsp5skkz4jlqr6tkvv2g9739ygrjupc4rkqd94mc7dfpj3pgx3f6w7qs9qyyssq7mf3fzcuxlmkr9nqatcch3u8uf4gjyawe052tejz8e9fqxu4pncqk3qklt8g6ylpshg09xyjquyrgtc72vcw5cp0dzcf406apyua7dgpnfn7an") |         expect(res["pr"]).to eq("lnbc50u1p3lwgknpp52g78gqya5euvzjc53fc6hkmlm2rfjhcd305tcmc0g9gaestav48sdq4gdhkven9v5sx6mmwv4ujzcqzpgxqyz5vqsp5skkz4jlqr6tkvv2g9739ygrjupc4rkqd94mc7dfpj3pgx3f6w7qs9qyyssq7mf3fzcuxlmkr9nqatcch3u8uf4gjyawe052tejz8e9fqxu4pncqk3qklt8g6ylpshg09xyjquyrgtc72vcw5cp0dzcf406apyua7dgpnfn7an") | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       context "amount too low" do |       describe "amount too low" do | ||||||
|         it "returns an error" do |         it "returns an error" do | ||||||
|           get lnurlpay_invoice_path(username: "satoshi", params: { |           get lnurlpay_invoice_path(username: "satoshi", params: { | ||||||
|             amount: 5000, comment: "Coffee time!" |             amount: 5000, comment: "Coffee time!" | ||||||
|           }) |           }) | ||||||
|  | 
 | ||||||
|           expect(response).to have_http_status(:ok) |           expect(response).to have_http_status(:ok) | ||||||
|  | 
 | ||||||
|           res = JSON.parse(response.body) |           res = JSON.parse(response.body) | ||||||
|           expect(res["status"]).to eq('ERROR') |           expect(res["status"]).to eq('ERROR') | ||||||
|           expect(res["reason"]).to eq('Invalid amount') |           expect(res["reason"]).to eq('Invalid amount') | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       context "comment too long" do |       describe "comment too long" do | ||||||
|         it "returns an error" do |         it "returns an error" do | ||||||
|           get lnurlpay_invoice_path(username: "satoshi", params: { |           get lnurlpay_invoice_path(username: "satoshi", params: { | ||||||
|             amount: 5000000, comment: "Coffee time is the best time, so here's some money for you to get some. May I suggest to sample some Pacamara beans from El Salvador?" |             amount: 5000000, comment: "Coffee time is the best time, so here's some money for you to get some. May I suggest to sample some Pacamara beans from El Salvador?" | ||||||
|           }) |           }) | ||||||
|  | 
 | ||||||
|           expect(response).to have_http_status(:ok) |           expect(response).to have_http_status(:ok) | ||||||
|  | 
 | ||||||
|           res = JSON.parse(response.body) |           res = JSON.parse(response.body) | ||||||
|           expect(res["status"]).to eq('ERROR') |           expect(res["status"]).to eq('ERROR') | ||||||
|           expect(res["reason"]).to eq('Comment too long') |           expect(res["reason"]).to eq('Comment too long') | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  | 
 | ||||||
|  |       context "zap request" do | ||||||
|  |         describe "with invalid request event" do | ||||||
|  |           it "returns an error" do | ||||||
|  |             get lnurlpay_invoice_path(username: "satoshi", params: { | ||||||
|  |               amount: 2100000, nostr: { foo: "bar" }.to_json | ||||||
|  |             }) | ||||||
|  | 
 | ||||||
|  |             res = JSON.parse(response.body) | ||||||
|  |             expect(res["status"]).to eq('ERROR') | ||||||
|  |             expect(res["reason"]).to eq('Invalid zap request') | ||||||
|  |           end | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         describe "with valid request event" do | ||||||
|  |           let(:event) { | ||||||
|  |             { | ||||||
|  |               id: "3cf02d7f0ccd9711c25098fc50b3a7ab880326e4e51cc8c7a7b59f147cff4fff", | ||||||
|  |               pubkey: "730b43e6f62c2ab22710b046e481802c8ac1108ed2cb9c21dff808d57ba24b6c", | ||||||
|  |               created_at: 1712487443, | ||||||
|  |               kind: 9734, | ||||||
|  |               tags: [ | ||||||
|  |                 ["relays", "wss://nostr.kosmos.org", "wss://relay.example.com"], | ||||||
|  |                 ["p", "07e188a1ff87ce171d517b8ed2bb7a31b1d3453a0db3b15379ec07b724d232f3"]], | ||||||
|  |               content: "", | ||||||
|  |               sig: "e9e9bb2bac4267a107ab5c3368f504b4f11b8e3b5ae875a1d63c74d6934138d2521dc35815b6f534fc5d803cbf633736d871886368bb8f92c4ad3837a68a06f2" | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  | 
 | ||||||
|  |           it "returns an invoice" do | ||||||
|  |             expect_any_instance_of(User).to receive(:ln_create_invoice) | ||||||
|  |               .with( | ||||||
|  |                 amount: 2100, | ||||||
|  |                 memo: "Zapped satoshi@kosmos.org on Nostr", | ||||||
|  |                 description_hash: "540279cd9da15279c8299d6d9ff1ab2a79eb259ee218adf3de393e1abe723077" | ||||||
|  |             ) | ||||||
|  |               .and_return("lnbc50u1p3lwgknpp52g78gqya5euvzjc53fc6hkmlm2rfjhcd305tcmc0g9gaestav48sdq4gdhkven9v5sx6mmwv4ujzcqzpgxqyz5vqsp5skkz4jlqr6tkvv2g9739ygrjupc4rkqd94mc7dfpj3pgx3f6w7qs9qyyssq7mf3fzcuxlmkr9nqatcch3u8uf4gjyawe052tejz8e9fqxu4pncqk3qklt8g6ylpshg09xyjquyrgtc72vcw5cp0dzcf406apyua7dgpnfn7an") | ||||||
|  | 
 | ||||||
|  |             get lnurlpay_invoice_path(username: "satoshi", params: { | ||||||
|  |               amount: 2100000, nostr: event.to_json | ||||||
|  |             }) | ||||||
|  | 
 | ||||||
|  |             expect(response).to have_http_status(:ok) | ||||||
|  | 
 | ||||||
|  |             res = JSON.parse(response.body) | ||||||
|  |             expect(res["status"]).to eq('OK') | ||||||
|  |             expect(res["pr"]).to match(/^lnbc/) | ||||||
|  |           end | ||||||
|  |         end | ||||||
|  |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     describe "GET /.well-known/keysend/:username/" do |     describe "GET /.well-known/keysend/:username/" do | ||||||
|  | |||||||
							
								
								
									
										206
									
								
								spec/services/nostr_manager/verify_zap_request_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								spec/services/nostr_manager/verify_zap_request_spec.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,206 @@ | |||||||
|  | require 'rails_helper' | ||||||
|  | 
 | ||||||
|  | RSpec.describe NostrManager::VerifyZapRequest, type: :model do | ||||||
|  |   describe "Signature invalid" do | ||||||
|  |     let(:event) { | ||||||
|  |       Nostr::Event.new( | ||||||
|  |         id: "3cf02d7f0ccd9711c25098fc50b3a7ab880326e4e51cc8c7a7b59f147cff4fff", | ||||||
|  |         pubkey: "730b43e6f62c2ab22710b046e481802c8ac1108ed2cb9c21dff808d57ba24b6c", | ||||||
|  |         created_at: 1712487443, | ||||||
|  |         kind: 9734, | ||||||
|  |         tags: [ | ||||||
|  |           ["relays", "wss://nostr.kosmos.org", "wss://relay.example.com"], | ||||||
|  |           ["p", "07e188a1ff87ce171d517b8ed2bb7a31b1d3453a0db3b15379ec07b724d232f3"]], | ||||||
|  |         content: "", | ||||||
|  |         sig: "1234562bac4267a107ab5c3368f504b4f11b8e3b5ae875a1d63c74d6934138d2521dc35815b6f534fc5d803cbf633736d871886368bb8f92c4ad3837a68a06f2" | ||||||
|  |       ) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     subject { | ||||||
|  |       NostrManager::VerifyZapRequest.call(amount: 100000, event: event, lnurl: nil) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     it "returns false" do | ||||||
|  |       expect(subject).to be(false) | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   describe "p tag missing" do | ||||||
|  |     let(:event) { | ||||||
|  |       Nostr::Event.new( | ||||||
|  |         id: "eb53c5e728b625831e318c7ab09373502dd4a41ed11c17f80f32fd1c3fe1252b", | ||||||
|  |         pubkey: "730b43e6f62c2ab22710b046e481802c8ac1108ed2cb9c21dff808d57ba24b6c", | ||||||
|  |         created_at: 1712580669, | ||||||
|  |         kind: 9734, | ||||||
|  |         tags: [["relays", "wss://nostr.kosmos.org","wss://relay.example.com"]], | ||||||
|  |         content: "", | ||||||
|  |         sig: "8e22dcb3e91d080c9549ea0808b018194cc352dde3056a4911796d6f0239de7e1955f287c7e6769909e59ab0ffa09e307178c32128dc451823fb00102ed7e80a" | ||||||
|  |       ) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     subject { | ||||||
|  |       NostrManager::VerifyZapRequest.call(amount: 100000, event: event, lnurl: nil) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     it "returns false" do | ||||||
|  |       expect(subject).to be(false) | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   describe "p tag not a valid pubkey" do | ||||||
|  |     let(:event) { | ||||||
|  |       Nostr::Event.new( | ||||||
|  |         id: "f2c23f038cf4d0307147d40ddceb87e34ee94acf632f5a67217a55a0b41c5d95", | ||||||
|  |         pubkey: "730b43e6f62c2ab22710b046e481802c8ac1108ed2cb9c21dff808d57ba24b6c", | ||||||
|  |         created_at: 1712581702, | ||||||
|  |         kind: 9734, | ||||||
|  |         tags: [ | ||||||
|  |           ["relays", "wss://nostr.kosmos.org","wss://relay.example.com"], | ||||||
|  |           ["p","123456abcdef"] | ||||||
|  |         ], | ||||||
|  |         content: "", | ||||||
|  |         sig: "b33e6b231273d38629f5efb86325ce3b4e02a7d84dfa1f37167ca2de8392cea654ae34000fc365ddfc6e21dc8ce2365fcb000ccb9064fbbcd54c7ea4a943955b" | ||||||
|  |       ) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     subject { | ||||||
|  |       NostrManager::VerifyZapRequest.call(amount: 100000, event: event, lnurl: nil) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     it "returns false" do | ||||||
|  |       expect(subject).to be(false) | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   describe "Minimum valid request" do | ||||||
|  |     let(:event) { | ||||||
|  |       Nostr::Event.new( | ||||||
|  |         id: "3cf02d7f0ccd9711c25098fc50b3a7ab880326e4e51cc8c7a7b59f147cff4fff", | ||||||
|  |         pubkey: "730b43e6f62c2ab22710b046e481802c8ac1108ed2cb9c21dff808d57ba24b6c", | ||||||
|  |         created_at: 1712487443, | ||||||
|  |         kind: 9734, | ||||||
|  |         tags: [ | ||||||
|  |           ["relays", "wss://nostr.kosmos.org", "wss://relay.example.com"], | ||||||
|  |           ["p", "07e188a1ff87ce171d517b8ed2bb7a31b1d3453a0db3b15379ec07b724d232f3"]], | ||||||
|  |         content: "", | ||||||
|  |         sig: "e9e9bb2bac4267a107ab5c3368f504b4f11b8e3b5ae875a1d63c74d6934138d2521dc35815b6f534fc5d803cbf633736d871886368bb8f92c4ad3837a68a06f2" | ||||||
|  |       ) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     subject { | ||||||
|  |       NostrManager::VerifyZapRequest.call(amount: 100000, event: event, lnurl: nil) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     it "returns true" do | ||||||
|  |       expect(subject).to be(true) | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   describe "Optional amount property" do | ||||||
|  |     describe "does not match given amount" do | ||||||
|  |       let(:event) { | ||||||
|  |         Nostr::Event.new( | ||||||
|  |           id: "be3d3ba15a257546f6fbba849d4717641fd4ea9f21ae6e9278a045f31d212c5e", | ||||||
|  |           pubkey: "730b43e6f62c2ab22710b046e481802c8ac1108ed2cb9c21dff808d57ba24b6c", | ||||||
|  |           created_at: 1712579812, | ||||||
|  |           kind: 9734, | ||||||
|  |           tags: [ | ||||||
|  |             ["relays", "wss://nostr.kosmos.org","wss://relay.example.com"], | ||||||
|  |             ["p", "07e188a1ff87ce171d517b8ed2bb7a31b1d3453a0db3b15379ec07b724d232f3"], | ||||||
|  |             ["amount", "21000"] | ||||||
|  |           ], | ||||||
|  |           content: "", | ||||||
|  |           sig: "2ca9cfd0fdaf43dd8a50ab586e83da4bd9d592def8ed198536f5e3e7aad3537818687e42d98eb61d60e33dbd848c1eecf72b68fd98376bbabdab7e029e810869" | ||||||
|  |         ) | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       subject { | ||||||
|  |         NostrManager::VerifyZapRequest.call(amount: 100000, event: event, lnurl: nil) | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       it "returns false" do | ||||||
|  |         expect(subject).to be(false) | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     describe "matches given amount" do | ||||||
|  |       let(:event) { | ||||||
|  |         Nostr::Event.new( | ||||||
|  |           id: "be3d3ba15a257546f6fbba849d4717641fd4ea9f21ae6e9278a045f31d212c5e", | ||||||
|  |           pubkey: "730b43e6f62c2ab22710b046e481802c8ac1108ed2cb9c21dff808d57ba24b6c", | ||||||
|  |           created_at: 1712579812, | ||||||
|  |           kind: 9734, | ||||||
|  |           tags: [ | ||||||
|  |             ["relays", "wss://nostr.kosmos.org","wss://relay.example.com"], | ||||||
|  |             ["p", "07e188a1ff87ce171d517b8ed2bb7a31b1d3453a0db3b15379ec07b724d232f3"], | ||||||
|  |             ["amount", "21000"] | ||||||
|  |           ], | ||||||
|  |           content: "", | ||||||
|  |           sig: "2ca9cfd0fdaf43dd8a50ab586e83da4bd9d592def8ed198536f5e3e7aad3537818687e42d98eb61d60e33dbd848c1eecf72b68fd98376bbabdab7e029e810869" | ||||||
|  |         ) | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       subject { | ||||||
|  |         NostrManager::VerifyZapRequest.call(amount: 21000, event: event, lnurl: nil) | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       it "returns true" do | ||||||
|  |         expect(subject).to be(true) | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   describe "Optional amount property" do | ||||||
|  |     describe "does not match given amount" do | ||||||
|  |       let(:event) { | ||||||
|  |         Nostr::Event.new( | ||||||
|  |           id: "be3d3ba15a257546f6fbba849d4717641fd4ea9f21ae6e9278a045f31d212c5e", | ||||||
|  |           pubkey: "730b43e6f62c2ab22710b046e481802c8ac1108ed2cb9c21dff808d57ba24b6c", | ||||||
|  |           created_at: 1712579812, | ||||||
|  |           kind: 9734, | ||||||
|  |           tags: [ | ||||||
|  |             ["relays", "wss://nostr.kosmos.org","wss://relay.example.com"], | ||||||
|  |             ["p", "07e188a1ff87ce171d517b8ed2bb7a31b1d3453a0db3b15379ec07b724d232f3"], | ||||||
|  |             ["amount", "21000"] | ||||||
|  |           ], | ||||||
|  |           content: "", | ||||||
|  |           sig: "2ca9cfd0fdaf43dd8a50ab586e83da4bd9d592def8ed198536f5e3e7aad3537818687e42d98eb61d60e33dbd848c1eecf72b68fd98376bbabdab7e029e810869" | ||||||
|  |         ) | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       subject { | ||||||
|  |         NostrManager::VerifyZapRequest.call(amount: 100000, event: event, lnurl: nil) | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       it "returns false" do | ||||||
|  |         expect(subject).to be(false) | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     describe "matches given amount" do | ||||||
|  |       let(:event) { | ||||||
|  |         Nostr::Event.new( | ||||||
|  |           id: "be3d3ba15a257546f6fbba849d4717641fd4ea9f21ae6e9278a045f31d212c5e", | ||||||
|  |           pubkey: "730b43e6f62c2ab22710b046e481802c8ac1108ed2cb9c21dff808d57ba24b6c", | ||||||
|  |           created_at: 1712579812, | ||||||
|  |           kind: 9734, | ||||||
|  |           tags: [ | ||||||
|  |             ["relays", "wss://nostr.kosmos.org","wss://relay.example.com"], | ||||||
|  |             ["p", "07e188a1ff87ce171d517b8ed2bb7a31b1d3453a0db3b15379ec07b724d232f3"], | ||||||
|  |             ["amount", "21000"] | ||||||
|  |           ], | ||||||
|  |           content: "", | ||||||
|  |           sig: "2ca9cfd0fdaf43dd8a50ab586e83da4bd9d592def8ed198536f5e3e7aad3537818687e42d98eb61d60e33dbd848c1eecf72b68fd98376bbabdab7e029e810869" | ||||||
|  |         ) | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       subject { | ||||||
|  |         NostrManager::VerifyZapRequest.call(amount: 21000, event: event, lnurl: nil) | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       it "returns true" do | ||||||
|  |         expect(subject).to be(true) | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user