l402_middleware 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/l402_middleware.rb +145 -0
  3. metadata +101 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 70f9855a816d04309f2ec16eb94b5f0385a17c8a4ca6588716f4a136ee29bbc5
4
+ data.tar.gz: f8185f1bb22374bbf2f5f541569fec57b508d2761082b8d070b9dcd97d555f5f
5
+ SHA512:
6
+ metadata.gz: a2e01af0cac5c6db1ad99f1cff29bfcacd13ec99ee9f96e3f00ac51f066a9f0a4021cabfb4cf50f5be2dfcd1092b3f719d3c92227bd95dd5c391b946a8e2bbab
7
+ data.tar.gz: c91b2f77ea8ac6322d7236039c15a90e73dd9848a64f1212e054102b1bac806d0a5eb4d636ca3677b25c806a541579cd30ba4b652c7d235dc73b859998ee523d
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+ require 'l402'
5
+ require 'l402_logger'
6
+ require 'l402_config'
7
+ require 'utils'
8
+ require 'constants'
9
+
10
+ module L402Middleware
11
+ class << self
12
+ attr_accessor :configuration
13
+ end
14
+
15
+ class Middleware
16
+ def initialize(app, config = nil)
17
+ @app = app
18
+ @config = L402Middleware::Configuration.new(config || default_config)
19
+
20
+ @config.validate!
21
+
22
+ verify_connect
23
+ end
24
+
25
+ def call(env)
26
+ token = extract_auth_token(env)
27
+ is_valid_l402_token, err = valid_l402_token?(token)
28
+
29
+ if free?(env['REQUEST_PATH'].to_s) || (is_valid_l402_token.to_s == "true" && err.nil?)
30
+ return allow_request(env)
31
+ end
32
+
33
+ invoke_payment(env[L402_AUTHORIZATION_HEADER].present?)
34
+ end
35
+
36
+ private
37
+
38
+ def default_config
39
+ if defined?(Rails)
40
+ config = Rails.configuration.try(:l402_middleware)
41
+ unless config
42
+ raise 'Rails configuration for L402Middleware is missing. Please pass config along with the L402Middleware'
43
+ end
44
+
45
+ config
46
+ else
47
+ unless L402Middleware.configuration
48
+ raise 'Configuration required for standalone mode. Use L402Middleware.configuration to set it.'
49
+ end
50
+
51
+ L402Middleware.configuration
52
+ end
53
+ end
54
+
55
+ def extract_auth_token(env)
56
+ auth_header = env[L402_AUTHORIZATION_HEADER]
57
+ auth_header&.strip
58
+ end
59
+
60
+ # Example token: L402 AGIAJEemVQUTEyNCR0exk7ek90Cg==:1234abcd1234abcd1234abcd
61
+ def valid_l402_token?(token)
62
+ return [false, 'missing L02 header'] unless token.to_s.downcase.start_with?("#{L402_HEADER} ")
63
+
64
+ token = token.sub(sub_l402_header_regex, "")
65
+
66
+ macaroon_part, preimage = token.split(':', 2)
67
+
68
+ return [false, 'missing macaroon or primage'] if macaroon_part.blank? || preimage.blank?
69
+
70
+ macaroons = macaroon_part.split(',').map(&:strip)
71
+
72
+ macaroons.each do |macaroon|
73
+ decoded_macaroon = Base64.strict_decode64(macaroon)
74
+ result, err = L402.verify_l402(decoded_macaroon, preimage, @config)
75
+
76
+ return [true, nil] if result.to_s == "true" && err.nil?
77
+ rescue StandardError => e
78
+ L402Logger.error("Error verifying macaroon: #{e.message}")
79
+ return [false, "error verifying macaroon: #{e.message}"]
80
+ end
81
+
82
+ return [false, 'unauthorized']
83
+ end
84
+
85
+ def allow_request(env)
86
+ @status, @headers, @response = @app.call(env)
87
+ [@status, @headers, @response]
88
+ end
89
+
90
+ def invoke_payment(is_unauthorized = false)
91
+ macaroon, invoice = L402.get_payment_request_details(@config)
92
+
93
+ status = 402
94
+ header = {
95
+ 'Content-Type' => 'application/json',
96
+ L402_CHALLENGE_HEADER => get_payment_header(macaroon, invoice)
97
+ }
98
+ response = is_unauthorized ? unauthorized_response : request_payment_response(macaroon, invoice)
99
+
100
+ [status, header, [response]]
101
+ end
102
+
103
+ def verify_connect
104
+ case @config.network_type
105
+ when :lnd
106
+ connect_to_lnd
107
+ when :lnurl
108
+ connect_to_lnurl
109
+ else
110
+ raise "Unsupported network type: #{@config.network_type}"
111
+ end
112
+ end
113
+
114
+ def connect_to_lnd
115
+ lnd_config = @config.lnd
116
+
117
+ begin
118
+ Lighstorm.connect!(
119
+ address: lnd_config[:address],
120
+ certificate_path: lnd_config[:tls_certificate_path],
121
+ macaroon_path: lnd_config[:macaroon_path]
122
+ )
123
+ L402Logger.info('Successfully connected to LND network')
124
+ rescue StandardError => e
125
+ L402Logger.error("Failed to connect to LND: #{e.message}\n#{e.backtrace.join("\n")}")
126
+ raise "Unable to establish connection with Lightning network: #{e.message}"
127
+ end
128
+ end
129
+
130
+ # Placeholder method
131
+ def connect_to_lnurl
132
+ @config.lnurl
133
+ raise 'integration with lnurl is WIP'
134
+ end
135
+
136
+ def free?(request)
137
+ @config.endpoints.each do |endpoint|
138
+ L402Logger.info("ENDPOINT: #{endpoint}, request :#{request}, regex: #{@config.endpoints}")
139
+ return false unless Regexp.new(endpoint).match(request).nil?
140
+ end
141
+
142
+ true
143
+ end
144
+ end
145
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: l402_middleware
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ritik Jain
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-12-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: google-protobuf
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 3.25.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 3.25.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: lighstorm
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: macaroons
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: A Ruby middleware implementation for the L402 protocol, leveraging macaroons
70
+ and the Lightning Network for secure authentication and payments.
71
+ email: ritikjain1272@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - lib/l402_middleware.rb
77
+ homepage: https://rubygems.org/gems/l402_middleware
78
+ licenses:
79
+ - MIT
80
+ metadata:
81
+ source_code_uri: https://github.com/rits1272/l402_middleware
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubygems_version: 3.2.3
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: L402 middleware for authentication and payment handling
101
+ test_files: []