Merge pull request 'Add LndHub wallets' (#33) from feature/lndhub into master
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #33
This commit is contained in:
commit
25ddab9241
@ -1 +1,3 @@
|
||||
EJABBERD_API_URL='https://xmpp.kosmos.org/api'
|
||||
LNDHUB_API_URL='http://localhost:3023'
|
||||
LNDHUB_PUBLIC_URL='https://lndhub.kosmos.org'
|
||||
|
@ -1 +1,3 @@
|
||||
EJABBERD_API_URL='https://xmpp.kosmos.org:5443/api'
|
||||
LNDHUB_API_URL='http://10.1.1.163:3023'
|
||||
LNDHUB_PUBLIC_URL='https://lndhub.kosmos.org'
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -42,3 +42,5 @@ yarn-debug.log*
|
||||
|
||||
# Ignore redis dumps from sidekiq
|
||||
dump.rdb
|
||||
|
||||
/config/credentials/development.key
|
||||
|
6
Gemfile
6
Gemfile
@ -24,12 +24,18 @@ gem 'bootsnap', '>= 1.4.2', require: false
|
||||
# Configuration
|
||||
gem 'dotenv-rails'
|
||||
|
||||
# Security
|
||||
gem 'lockbox'
|
||||
|
||||
# Authentication
|
||||
gem 'warden'
|
||||
gem 'devise'
|
||||
gem 'devise_ldap_authenticatable'
|
||||
gem 'net-ldap'
|
||||
|
||||
# Utilities
|
||||
gem "rqrcode", "~> 2.0"
|
||||
|
||||
# HTTP requests
|
||||
gem 'faraday'
|
||||
|
||||
|
285
Gemfile.lock
285
Gemfile.lock
@ -1,84 +1,91 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actioncable (6.0.3.4)
|
||||
actionpack (= 6.0.3.4)
|
||||
actioncable (6.0.4.1)
|
||||
actionpack (= 6.0.4.1)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
actionmailbox (6.0.3.4)
|
||||
actionpack (= 6.0.3.4)
|
||||
activejob (= 6.0.3.4)
|
||||
activerecord (= 6.0.3.4)
|
||||
activestorage (= 6.0.3.4)
|
||||
activesupport (= 6.0.3.4)
|
||||
actionmailbox (6.0.4.1)
|
||||
actionpack (= 6.0.4.1)
|
||||
activejob (= 6.0.4.1)
|
||||
activerecord (= 6.0.4.1)
|
||||
activestorage (= 6.0.4.1)
|
||||
activesupport (= 6.0.4.1)
|
||||
mail (>= 2.7.1)
|
||||
actionmailer (6.0.3.4)
|
||||
actionpack (= 6.0.3.4)
|
||||
actionview (= 6.0.3.4)
|
||||
activejob (= 6.0.3.4)
|
||||
actionmailer (6.0.4.1)
|
||||
actionpack (= 6.0.4.1)
|
||||
actionview (= 6.0.4.1)
|
||||
activejob (= 6.0.4.1)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (6.0.3.4)
|
||||
actionview (= 6.0.3.4)
|
||||
activesupport (= 6.0.3.4)
|
||||
actionpack (6.0.4.1)
|
||||
actionview (= 6.0.4.1)
|
||||
activesupport (= 6.0.4.1)
|
||||
rack (~> 2.0, >= 2.0.8)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
actiontext (6.0.3.4)
|
||||
actionpack (= 6.0.3.4)
|
||||
activerecord (= 6.0.3.4)
|
||||
activestorage (= 6.0.3.4)
|
||||
activesupport (= 6.0.3.4)
|
||||
actiontext (6.0.4.1)
|
||||
actionpack (= 6.0.4.1)
|
||||
activerecord (= 6.0.4.1)
|
||||
activestorage (= 6.0.4.1)
|
||||
activesupport (= 6.0.4.1)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (6.0.3.4)
|
||||
activesupport (= 6.0.3.4)
|
||||
actionview (6.0.4.1)
|
||||
activesupport (= 6.0.4.1)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
||||
activejob (6.0.3.4)
|
||||
activesupport (= 6.0.3.4)
|
||||
activejob (6.0.4.1)
|
||||
activesupport (= 6.0.4.1)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (6.0.3.4)
|
||||
activesupport (= 6.0.3.4)
|
||||
activerecord (6.0.3.4)
|
||||
activemodel (= 6.0.3.4)
|
||||
activesupport (= 6.0.3.4)
|
||||
activestorage (6.0.3.4)
|
||||
actionpack (= 6.0.3.4)
|
||||
activejob (= 6.0.3.4)
|
||||
activerecord (= 6.0.3.4)
|
||||
marcel (~> 0.3.1)
|
||||
activesupport (6.0.3.4)
|
||||
activemodel (6.0.4.1)
|
||||
activesupport (= 6.0.4.1)
|
||||
activerecord (6.0.4.1)
|
||||
activemodel (= 6.0.4.1)
|
||||
activesupport (= 6.0.4.1)
|
||||
activestorage (6.0.4.1)
|
||||
actionpack (= 6.0.4.1)
|
||||
activejob (= 6.0.4.1)
|
||||
activerecord (= 6.0.4.1)
|
||||
marcel (~> 1.0.0)
|
||||
activesupport (6.0.4.1)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 0.7, < 2)
|
||||
minitest (~> 5.1)
|
||||
tzinfo (~> 1.1)
|
||||
zeitwerk (~> 2.2, >= 2.2.2)
|
||||
addressable (2.7.0)
|
||||
addressable (2.8.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
bcrypt (3.1.16)
|
||||
bindex (0.8.1)
|
||||
bootsnap (1.5.0)
|
||||
bootsnap (1.9.1)
|
||||
msgpack (~> 1.0)
|
||||
builder (3.2.4)
|
||||
byebug (11.1.3)
|
||||
capybara (3.33.0)
|
||||
capybara (3.36.0)
|
||||
addressable
|
||||
matrix
|
||||
mini_mime (>= 0.1.3)
|
||||
nokogiri (~> 1.8)
|
||||
rack (>= 1.6.0)
|
||||
rack-test (>= 0.6.3)
|
||||
regexp_parser (~> 1.5)
|
||||
regexp_parser (>= 1.5, < 3.0)
|
||||
xpath (~> 3.2)
|
||||
concurrent-ruby (1.1.7)
|
||||
connection_pool (2.2.3)
|
||||
crack (0.4.3)
|
||||
safe_yaml (~> 1.0.0)
|
||||
chunky_png (1.4.0)
|
||||
concurrent-ruby (1.1.9)
|
||||
connection_pool (2.2.5)
|
||||
crack (0.4.5)
|
||||
rexml
|
||||
crass (1.0.6)
|
||||
database_cleaner (1.8.5)
|
||||
devise (4.7.3)
|
||||
database_cleaner (2.0.1)
|
||||
database_cleaner-active_record (~> 2.0.0)
|
||||
database_cleaner-active_record (2.0.1)
|
||||
activerecord (>= 5.a)
|
||||
database_cleaner-core (~> 2.0.0)
|
||||
database_cleaner-core (2.0.1)
|
||||
devise (4.8.0)
|
||||
bcrypt (~> 3.0)
|
||||
orm_adapter (~> 0.1)
|
||||
railties (>= 4.1.0)
|
||||
@ -88,127 +95,149 @@ GEM
|
||||
devise (>= 3.4.1)
|
||||
net-ldap (>= 0.16.0)
|
||||
diff-lcs (1.4.4)
|
||||
dotenv (2.7.2)
|
||||
dotenv-rails (2.7.2)
|
||||
dotenv (= 2.7.2)
|
||||
railties (>= 3.2, < 6.1)
|
||||
dotenv (2.7.6)
|
||||
dotenv-rails (2.7.6)
|
||||
dotenv (= 2.7.6)
|
||||
railties (>= 3.2)
|
||||
e2mmap (0.1.0)
|
||||
erubi (1.9.0)
|
||||
et-orbi (1.2.4)
|
||||
erubi (1.10.0)
|
||||
et-orbi (1.2.6)
|
||||
tzinfo
|
||||
factory_bot (6.1.0)
|
||||
factory_bot (6.2.0)
|
||||
activesupport (>= 5.0.0)
|
||||
factory_bot_rails (6.1.0)
|
||||
factory_bot (~> 6.1.0)
|
||||
factory_bot_rails (6.2.0)
|
||||
factory_bot (~> 6.2.0)
|
||||
railties (>= 5.0.0)
|
||||
faraday (0.17.0)
|
||||
faraday (1.8.0)
|
||||
faraday-em_http (~> 1.0)
|
||||
faraday-em_synchrony (~> 1.0)
|
||||
faraday-excon (~> 1.1)
|
||||
faraday-httpclient (~> 1.0.1)
|
||||
faraday-net_http (~> 1.0)
|
||||
faraday-net_http_persistent (~> 1.1)
|
||||
faraday-patron (~> 1.0)
|
||||
faraday-rack (~> 1.0)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
ffi (1.13.1)
|
||||
fugit (1.4.2)
|
||||
ruby2_keywords (>= 0.0.4)
|
||||
faraday-em_http (1.0.0)
|
||||
faraday-em_synchrony (1.0.0)
|
||||
faraday-excon (1.1.0)
|
||||
faraday-httpclient (1.0.1)
|
||||
faraday-net_http (1.0.1)
|
||||
faraday-net_http_persistent (1.2.0)
|
||||
faraday-patron (1.0.0)
|
||||
faraday-rack (1.0.0)
|
||||
ffi (1.15.4)
|
||||
fugit (1.5.2)
|
||||
et-orbi (~> 1.1, >= 1.1.8)
|
||||
raabro (~> 1.4)
|
||||
globalid (0.4.2)
|
||||
activesupport (>= 4.2.0)
|
||||
hashdiff (0.4.0)
|
||||
i18n (1.8.5)
|
||||
globalid (0.5.2)
|
||||
activesupport (>= 5.0)
|
||||
hashdiff (1.0.1)
|
||||
i18n (1.8.11)
|
||||
concurrent-ruby (~> 1.0)
|
||||
jbuilder (2.10.1)
|
||||
jbuilder (2.11.3)
|
||||
activesupport (>= 5.0.0)
|
||||
launchy (2.4.3)
|
||||
addressable (~> 2.3)
|
||||
launchy (2.5.0)
|
||||
addressable (~> 2.7)
|
||||
letter_opener (1.7.0)
|
||||
launchy (~> 2.2)
|
||||
letter_opener_web (1.3.4)
|
||||
letter_opener_web (1.4.1)
|
||||
actionmailer (>= 3.2)
|
||||
letter_opener (~> 1.0)
|
||||
railties (>= 3.2)
|
||||
listen (3.2.1)
|
||||
listen (3.7.0)
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
loofah (2.7.0)
|
||||
lockbox (0.6.6)
|
||||
loofah (2.12.0)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.5.9)
|
||||
mail (2.7.1)
|
||||
mini_mime (>= 0.1.1)
|
||||
marcel (0.3.3)
|
||||
mimemagic (~> 0.3.2)
|
||||
marcel (1.0.2)
|
||||
matrix (0.4.2)
|
||||
method_source (1.0.0)
|
||||
mimemagic (0.3.5)
|
||||
mini_mime (1.0.2)
|
||||
mini_portile2 (2.4.0)
|
||||
minitest (5.14.2)
|
||||
msgpack (1.3.3)
|
||||
mini_mime (1.1.2)
|
||||
minitest (5.14.4)
|
||||
msgpack (1.4.2)
|
||||
multipart-post (2.1.1)
|
||||
net-ldap (0.16.3)
|
||||
nio4r (2.5.4)
|
||||
nokogiri (1.10.10)
|
||||
mini_portile2 (~> 2.4.0)
|
||||
net-ldap (0.17.0)
|
||||
nio4r (2.5.8)
|
||||
nokogiri (1.12.5-x86_64-linux)
|
||||
racc (~> 1.4)
|
||||
orm_adapter (0.5.0)
|
||||
pg (1.2.3)
|
||||
public_suffix (4.0.6)
|
||||
puma (4.3.6)
|
||||
puma (4.3.10)
|
||||
nio4r (~> 2.0)
|
||||
raabro (1.4.0)
|
||||
racc (1.6.0)
|
||||
rack (2.2.3)
|
||||
rack-proxy (0.6.5)
|
||||
rack-proxy (0.7.0)
|
||||
rack
|
||||
rack-test (1.1.0)
|
||||
rack (>= 1.0, < 3)
|
||||
rails (6.0.3.4)
|
||||
actioncable (= 6.0.3.4)
|
||||
actionmailbox (= 6.0.3.4)
|
||||
actionmailer (= 6.0.3.4)
|
||||
actionpack (= 6.0.3.4)
|
||||
actiontext (= 6.0.3.4)
|
||||
actionview (= 6.0.3.4)
|
||||
activejob (= 6.0.3.4)
|
||||
activemodel (= 6.0.3.4)
|
||||
activerecord (= 6.0.3.4)
|
||||
activestorage (= 6.0.3.4)
|
||||
activesupport (= 6.0.3.4)
|
||||
rails (6.0.4.1)
|
||||
actioncable (= 6.0.4.1)
|
||||
actionmailbox (= 6.0.4.1)
|
||||
actionmailer (= 6.0.4.1)
|
||||
actionpack (= 6.0.4.1)
|
||||
actiontext (= 6.0.4.1)
|
||||
actionview (= 6.0.4.1)
|
||||
activejob (= 6.0.4.1)
|
||||
activemodel (= 6.0.4.1)
|
||||
activerecord (= 6.0.4.1)
|
||||
activestorage (= 6.0.4.1)
|
||||
activesupport (= 6.0.4.1)
|
||||
bundler (>= 1.3.0)
|
||||
railties (= 6.0.3.4)
|
||||
railties (= 6.0.4.1)
|
||||
sprockets-rails (>= 2.0.0)
|
||||
rails-dom-testing (2.0.3)
|
||||
activesupport (>= 4.2.0)
|
||||
nokogiri (>= 1.6)
|
||||
rails-html-sanitizer (1.3.0)
|
||||
rails-html-sanitizer (1.4.2)
|
||||
loofah (~> 2.3)
|
||||
railties (6.0.3.4)
|
||||
actionpack (= 6.0.3.4)
|
||||
activesupport (= 6.0.3.4)
|
||||
railties (6.0.4.1)
|
||||
actionpack (= 6.0.4.1)
|
||||
activesupport (= 6.0.4.1)
|
||||
method_source
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.20.3, < 2.0)
|
||||
rake (13.0.1)
|
||||
rb-fsevent (0.10.4)
|
||||
rake (13.0.6)
|
||||
rb-fsevent (0.11.0)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
redis (4.2.5)
|
||||
regexp_parser (1.8.2)
|
||||
redis (4.5.1)
|
||||
regexp_parser (2.1.1)
|
||||
responders (3.0.1)
|
||||
actionpack (>= 5.0)
|
||||
railties (>= 5.0)
|
||||
rspec-core (3.10.0)
|
||||
rexml (3.2.5)
|
||||
rqrcode (2.1.0)
|
||||
chunky_png (~> 1.0)
|
||||
rqrcode_core (~> 1.0)
|
||||
rqrcode_core (1.2.0)
|
||||
rspec-core (3.10.1)
|
||||
rspec-support (~> 3.10.0)
|
||||
rspec-expectations (3.10.0)
|
||||
rspec-expectations (3.10.1)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.10.0)
|
||||
rspec-mocks (3.10.0)
|
||||
rspec-mocks (3.10.2)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.10.0)
|
||||
rspec-rails (4.0.1)
|
||||
actionpack (>= 4.2)
|
||||
activesupport (>= 4.2)
|
||||
railties (>= 4.2)
|
||||
rspec-core (~> 3.9)
|
||||
rspec-expectations (~> 3.9)
|
||||
rspec-mocks (~> 3.9)
|
||||
rspec-support (~> 3.9)
|
||||
rspec-support (3.10.0)
|
||||
rufus-scheduler (3.7.0)
|
||||
rspec-rails (5.0.2)
|
||||
actionpack (>= 5.2)
|
||||
activesupport (>= 5.2)
|
||||
railties (>= 5.2)
|
||||
rspec-core (~> 3.10)
|
||||
rspec-expectations (~> 3.10)
|
||||
rspec-mocks (~> 3.10)
|
||||
rspec-support (~> 3.10)
|
||||
rspec-support (3.10.3)
|
||||
ruby2_keywords (0.0.5)
|
||||
rufus-scheduler (3.8.0)
|
||||
fugit (~> 1.1, >= 1.1.6)
|
||||
safe_yaml (1.0.5)
|
||||
sass-rails (6.0.0)
|
||||
sassc-rails (~> 2.1, >= 2.1.1)
|
||||
sassc (2.4.0)
|
||||
@ -219,11 +248,11 @@ GEM
|
||||
sprockets (> 3.0)
|
||||
sprockets-rails
|
||||
tilt
|
||||
sidekiq (6.1.3)
|
||||
sidekiq (6.3.1)
|
||||
connection_pool (>= 2.2.2)
|
||||
rack (~> 2.0)
|
||||
redis (>= 4.2.0)
|
||||
sidekiq-scheduler (3.0.1)
|
||||
sidekiq-scheduler (3.1.0)
|
||||
e2mmap
|
||||
redis (>= 3, < 5)
|
||||
rufus-scheduler (~> 3.2)
|
||||
@ -237,12 +266,12 @@ GEM
|
||||
sprockets (4.0.2)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (> 1, < 3)
|
||||
sprockets-rails (3.2.2)
|
||||
actionpack (>= 4.0)
|
||||
activesupport (>= 4.0)
|
||||
sprockets-rails (3.4.0)
|
||||
actionpack (>= 5.2)
|
||||
activesupport (>= 5.2)
|
||||
sprockets (>= 3.0.0)
|
||||
sqlite3 (1.4.2)
|
||||
thor (1.0.1)
|
||||
thor (1.1.0)
|
||||
thread_safe (0.3.6)
|
||||
thwait (0.2.0)
|
||||
e2mmap
|
||||
@ -250,29 +279,29 @@ GEM
|
||||
turbolinks (5.2.1)
|
||||
turbolinks-source (~> 5.2)
|
||||
turbolinks-source (5.2.0)
|
||||
tzinfo (1.2.7)
|
||||
tzinfo (1.2.9)
|
||||
thread_safe (~> 0.1)
|
||||
warden (1.2.9)
|
||||
rack (>= 2.0.9)
|
||||
web-console (4.1.0)
|
||||
web-console (4.2.0)
|
||||
actionview (>= 6.0.0)
|
||||
activemodel (>= 6.0.0)
|
||||
bindex (>= 0.4.0)
|
||||
railties (>= 6.0.0)
|
||||
webmock (3.6.0)
|
||||
addressable (>= 2.3.6)
|
||||
webmock (3.14.0)
|
||||
addressable (>= 2.8.0)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
webpacker (4.3.0)
|
||||
activesupport (>= 4.2)
|
||||
rack-proxy (>= 0.6.1)
|
||||
railties (>= 4.2)
|
||||
websocket-driver (0.7.3)
|
||||
websocket-driver (0.7.5)
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.5)
|
||||
xpath (3.2.0)
|
||||
nokogiri (~> 1.8)
|
||||
zeitwerk (2.4.1)
|
||||
zeitwerk (2.5.1)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
@ -292,10 +321,12 @@ DEPENDENCIES
|
||||
letter_opener
|
||||
letter_opener_web
|
||||
listen (~> 3.2)
|
||||
lockbox
|
||||
net-ldap
|
||||
pg (~> 1.2.3)
|
||||
puma (~> 4.1)
|
||||
rails (~> 6.0.3, >= 6.0.3.4)
|
||||
rqrcode (~> 2.0)
|
||||
rspec-rails
|
||||
sass-rails (>= 6)
|
||||
sidekiq
|
||||
|
57
app/controllers/lnurlpay_controller.rb
Normal file
57
app/controllers/lnurlpay_controller.rb
Normal file
@ -0,0 +1,57 @@
|
||||
class LnurlpayController < ApplicationController
|
||||
before_action :find_user_by_address
|
||||
|
||||
def index
|
||||
render json: {
|
||||
status: "OK",
|
||||
callback: "https://accounts.kosmos.org/lnurlpay/#{@user.address}/invoice",
|
||||
tag: "payRequest",
|
||||
maxSendable: 1000000,
|
||||
minSendable: 1000,
|
||||
metadata: metadata(@user.address),
|
||||
commentAllowed: 0
|
||||
}
|
||||
end
|
||||
|
||||
def invoice
|
||||
amount = params[:amount].to_i # msats
|
||||
address = params[:address]
|
||||
|
||||
validate_amount(amount)
|
||||
|
||||
payment_request = @user.ln_create_invoice({
|
||||
amount: amount,
|
||||
description_hash: Digest::SHA2.hexdigest(metadata(address))
|
||||
})
|
||||
|
||||
render json: {
|
||||
status: "OK",
|
||||
successAction: {
|
||||
tag: "message",
|
||||
message: "Payment received. Thanks!"
|
||||
},
|
||||
routes: [],
|
||||
pr: payment_request
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_user_by_address
|
||||
address = params[:address].split("@")
|
||||
@user = User.where(cn: address.first, ou: address.last).first
|
||||
http_status :not_found if @user.nil?
|
||||
end
|
||||
|
||||
def metadata(address)
|
||||
"[[\"text/identifier\", \"#{address}\"], [\"text/plain\", \"Sats for #{address}\"]]"
|
||||
end
|
||||
|
||||
def validate_amount(amount)
|
||||
if amount > 1000000 || amount < 1000
|
||||
render json: { status: "ERROR", reason: "Invalid amount" }
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
end
|
44
app/controllers/wallet_controller.rb
Normal file
44
app/controllers/wallet_controller.rb
Normal file
@ -0,0 +1,44 @@
|
||||
require "rqrcode"
|
||||
|
||||
class WalletController < ApplicationController
|
||||
before_action :require_user_signed_in
|
||||
before_action :authenticate_with_lndhub
|
||||
|
||||
def index
|
||||
@current_section = :wallet
|
||||
|
||||
@wallet_url = "lndhub://#{current_user.ln_login}:#{current_user.ln_password}@#{ENV['LNDHUB_PUBLIC_URL']}"
|
||||
|
||||
qrcode = RQRCode::QRCode.new(@wallet_url)
|
||||
@svg = qrcode.as_svg(
|
||||
color: "000",
|
||||
shape_rendering: "crispEdges",
|
||||
module_size: 6,
|
||||
standalone: true,
|
||||
use_path: true
|
||||
)
|
||||
|
||||
@balance = fetch_balance rescue nil
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def authenticate_with_lndhub
|
||||
if session["ln_auth_token"].present?
|
||||
@ln_auth_token = session["ln_auth_token"]
|
||||
else
|
||||
lndhub = Lndhub.new
|
||||
auth_token = lndhub.authenticate(current_user)
|
||||
session["ln_auth_token"] = auth_token
|
||||
@ln_auth_token = auth_token
|
||||
end
|
||||
rescue
|
||||
# TODO add exception tracking
|
||||
end
|
||||
|
||||
def fetch_balance
|
||||
lndhub = Lndhub.new
|
||||
data = lndhub.balance @ln_auth_token
|
||||
data["BTC"]["AvailableBalance"]
|
||||
end
|
||||
end
|
2
app/helpers/lnurlpay_helper.rb
Normal file
2
app/helpers/lnurlpay_helper.rb
Normal file
@ -0,0 +1,2 @@
|
||||
module LnurlpayHelper
|
||||
end
|
2
app/helpers/wallet_helper.rb
Normal file
2
app/helpers/wallet_helper.rb
Normal file
@ -0,0 +1,2 @@
|
||||
module WalletHelper
|
||||
end
|
13
app/jobs/create_lndhub_wallet_job.rb
Normal file
13
app/jobs/create_lndhub_wallet_job.rb
Normal file
@ -0,0 +1,13 @@
|
||||
class CreateLndhubWalletJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
def perform(user)
|
||||
return if user.ln_login.present? && user.ln_password.present?
|
||||
|
||||
lndhub = Lndhub.new
|
||||
credentials = lndhub.create({ partnerid: user.ou, accounttype: "user" })
|
||||
|
||||
user.update! ln_login: credentials["login"],
|
||||
ln_password: credentials["password"]
|
||||
end
|
||||
end
|
@ -10,6 +10,9 @@ class User < ApplicationRecord
|
||||
validates_uniqueness_of :email
|
||||
validates :email, email: true
|
||||
|
||||
encrypts :ln_login
|
||||
encrypts :ln_password
|
||||
|
||||
# Include default devise modules. Others available are:
|
||||
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
|
||||
devise :ldap_authenticatable,
|
||||
@ -53,4 +56,10 @@ class User < ApplicationRecord
|
||||
self.valid?
|
||||
self.errors[attribute_name].blank?
|
||||
end
|
||||
|
||||
def ln_create_invoice(payload)
|
||||
lndhub = Lndhub.new
|
||||
lndhub.authenticate self
|
||||
lndhub.addinvoice payload
|
||||
end
|
||||
end
|
||||
|
@ -10,6 +10,7 @@ class CreateAccount < ApplicationService
|
||||
def call
|
||||
user = create_user_in_database
|
||||
add_ldap_document
|
||||
create_lndhub_wallet
|
||||
|
||||
if @invitation.present?
|
||||
update_invitation(user.id)
|
||||
@ -44,4 +45,8 @@ class CreateAccount < ApplicationService
|
||||
return if Rails.env.development?
|
||||
ExchangeXmppContactsJob.perform_later(@invitation.user, @username, @domain)
|
||||
end
|
||||
|
||||
def create_lndhub_wallet
|
||||
CreateLndhubWalletJob.perform_later(user)
|
||||
end
|
||||
end
|
||||
|
57
app/services/lndhub.rb
Normal file
57
app/services/lndhub.rb
Normal file
@ -0,0 +1,57 @@
|
||||
class Lndhub
|
||||
attr_accessor :auth_token
|
||||
|
||||
def initialize
|
||||
@base_url = ENV["LNDHUB_API_URL"]
|
||||
end
|
||||
|
||||
def post(endpoint, payload)
|
||||
headers = { "Content-Type" => "application/json" }
|
||||
if auth_token
|
||||
headers.merge!({ "Authorization" => "Bearer #{auth_token}" })
|
||||
end
|
||||
|
||||
res = Faraday.post "#{@base_url}/#{endpoint}", payload.to_json, headers
|
||||
|
||||
if res.status != 200
|
||||
Rails.logger.error "[lndhub] API request failed:"
|
||||
Rails.logger.error res.body
|
||||
#TODO add some kind of exception tracking/notifications
|
||||
end
|
||||
|
||||
JSON.parse(res.body)
|
||||
end
|
||||
|
||||
def get(endpoint, auth_token)
|
||||
res = Faraday.get("#{@base_url}/#{endpoint}", {}, {
|
||||
"Content-Type" => "application/json",
|
||||
"Accept" => "application/json",
|
||||
"Authorization" => "Bearer #{auth_token}"
|
||||
})
|
||||
|
||||
JSON.parse(res.body)
|
||||
end
|
||||
|
||||
def create(payload)
|
||||
post "create", payload
|
||||
end
|
||||
|
||||
def authenticate(user)
|
||||
credentials = post "auth?type=auth", { login: user.ln_login, password: user.ln_password }
|
||||
self.auth_token = credentials["access_token"]
|
||||
self.auth_token
|
||||
end
|
||||
|
||||
def balance(user_token)
|
||||
get "balance", user_token || auth_token
|
||||
end
|
||||
|
||||
def addinvoice(payload)
|
||||
invoice = post "addinvoice", {
|
||||
amt: payload[:amount],
|
||||
description_hash: payload[:description_hash]
|
||||
}
|
||||
|
||||
invoice["payment_request"]
|
||||
end
|
||||
end
|
@ -13,6 +13,10 @@
|
||||
<%= link_to "Donations", donations_path,
|
||||
class: @current_section == :contributions ? "active" : nil %>
|
||||
</li>
|
||||
<li>
|
||||
<%= link_to "Wallet", wallet_path,
|
||||
class: @current_section == :wallet ? "active" : nil %>
|
||||
</li>
|
||||
<li>
|
||||
<%= link_to "Security", security_path,
|
||||
class: @current_section == :security ? "active" : nil %>
|
||||
|
54
app/views/wallet/index.html.erb
Normal file
54
app/views/wallet/index.html.erb
Normal file
@ -0,0 +1,54 @@
|
||||
<section class="w-full grid grid-cols-1 md:grid-cols-2">
|
||||
<div>
|
||||
<h2>Wallet</h2>
|
||||
<p>
|
||||
Send and receive BTC via the Lightning Network.
|
||||
</p>
|
||||
</div>
|
||||
<p class="font-mono mt-4 md:text-right md:mt-0">
|
||||
<% if @balance %>
|
||||
<span class="text-xl"><%= @balance %> sats</span><br>
|
||||
<span class="text-sm text-gray-500">Available balance</span>
|
||||
<% end %>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>Blue Wallet</h3>
|
||||
<p>
|
||||
You can connect
|
||||
<%= link_to "Blue Wallet", "https://bluewallet.io",
|
||||
class: "ks-text-link", target: "_blank" %>
|
||||
(Android or iOS) to your Kosmos lightning wallet. In order to do so,
|
||||
scan the setup QR code from the Import Wallet screen in the app.
|
||||
</p>
|
||||
<p>
|
||||
<a id="show-setup-code" class="ks-text-link cursor-pointer">Show setup code</a>
|
||||
<a id="hide-setup-code" class="ks-text-link cursor-pointer" style="display: none;">Hide setup code</a>
|
||||
</p>
|
||||
<p id="setup-code" style="display: none;">
|
||||
<%= raw @svg %>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<script type="text/javascript">
|
||||
let linkShow = document.querySelector('#show-setup-code');
|
||||
let linkHide = document.querySelector('#hide-setup-code');
|
||||
let setupCode = document.querySelector('#setup-code');
|
||||
|
||||
linkShow.addEventListener('click', function(ev) {
|
||||
ev.preventDefault();
|
||||
setupCode.style.display = 'block';
|
||||
linkShow.style.display = 'none';
|
||||
linkHide.style.display = 'block';
|
||||
window.scrollTo(0, document.body.scrollHeight);
|
||||
});
|
||||
|
||||
linkHide.addEventListener('click', function(ev) {
|
||||
ev.preventDefault();
|
||||
const el = document.querySelector('#setup-code');
|
||||
setupCode.style.display = 'none';
|
||||
linkShow.style.display = 'block';
|
||||
linkHide.style.display = 'none';
|
||||
});
|
||||
</script>
|
@ -1 +1 @@
|
||||
LXwVUXfG3P3NMBp56xEQHKY4YABoVvECgctVLuj4XRkCUKQURUC3pt60yBbMfw8Qs7yH1oeNiUv5ouoNrxR35PiquFr05oIPoHbHewB/aRShe7y313q1iXfddfYnom9r7wEETkeuFLBULNrLjJjzlgJgB8A9lmcSKMy9lEdGKJ5LghA6pEGq4KRxlixr8vC8ExcDtdENuxSWPU97cc5YHGjTTaiB9XIM61xtGcBUcREaizSyzloeRjPee71GfWKfVx3XNTQDoKfs6cecWhrSLlOVjsWGoiGlwpff3cPo1pSuYIoNo/YRnfHEr1WTw/+R3nc0wgPMBZSmFLK/8Uunzr8T6Q3vqqWB1QnKBquOcASa8jRaPFBs5k8PUeCT6aYdVBV0GSOGlyll2dBtfwrZgt2ssk24BuqK5pru5vIdhWNR7zl3+R0o2ABLTEcBSuxe754NiPasEKRQ8/K4lojOjnOcwdhdqC7jN2RVS5G03ZgHEqk1m+Z9svtu9PaRAD8I9vrpCQfq9Bifm2qZUSBJrgexHtDnSMfg/36hCUeyd2z0naoq3IWJ/xyCf1S5uzyd5MPh7N76L9FudD5nK39Jrj+yuVayAXQ1M9K89kSCiC2/ZbBE--TCbSksW4umkXZY62--jE6cZdM44o8/AWe7alnotA==
|
||||
PRI1laGy6XiLpsII0ixFOTCpzzDbrRpIQ7GJ2flvA+UEEiPVQQ4e/pt6ZjumaZ/geTBHCRZklLtS1u6HjucVKHGSR4K/lE1q7u6nfi/wAvwGQdCTJeKf8PetdlsiVZg2OW4Wi2YF7qtb1ipGS/uRlOeLP8JOwp5BNVS1J6tvNX4T5gA7rrB4Cvtfwp1dwLWODHiXbeZK7SN2j7V3NPGZl0LbNg2jquC4DzQOBhMOlwu1IAgOAcqKbHh9tDabpVOcOD5pNSaVaoBO01P8ObbX8x0S0Ug7BPkM5nnyJTQdNH7LHKvtNmrUEk7+fd+VZR6WqEp6SFBoAA7XxvOLy9dIOqvXbAYnrNZX7iI4IpgZWRNIQ7G1qSBjpyPLKC7+nSPmvd4IcgCHVUBdYp0+yYDxLzwuuhPVtyAY4JAIdZY1mhYxx7BzGNiMc3p8AlMS6hPeO9lVQZykViBGnTjR+iah9OQYAihX9FYywtBkNvMXLiYqsVZmv6em9Uk/ivKSIsaFwNwrelCI5H4Q/+/hKFJ1JaMjbYheXCJgcGgfhiC+fIHig/8y8rXd9lWGa1T+PrpA8akcq/K8I6gbxYxpLWcy5Vnz/SyaMurLPVfCq4cD/JfpLSfy0HophaiycZ7D6dr43rnHsPfrt6kveDOgWUK9d7CqHxsWdXbCpJeBoh8/1usIsGsmyhfwHq0dEpRx78bR2EJeM4LOAuQgf69/5rFJydIbXq76l1BftTls1Pgh--OI8c/RQGQ30wT1Ff--M/ltnmdl+FRdlNliTb79lg==
|
1
config/credentials/development.yml.enc
Normal file
1
config/credentials/development.yml.enc
Normal file
@ -0,0 +1 @@
|
||||
Ga2G0A==--RCOGf20OFDHTm7qw--PLI8AZQQylfrplQVYg603Q==
|
@ -1,7 +1,6 @@
|
||||
require 'sidekiq/web'
|
||||
|
||||
Rails.application.routes.draw do
|
||||
resources :donations
|
||||
devise_for :users
|
||||
|
||||
get 'welcome', to: 'welcome#index'
|
||||
@ -18,6 +17,13 @@ Rails.application.routes.draw do
|
||||
|
||||
resources :invitations, only: ['index', 'show', 'create', 'destroy']
|
||||
|
||||
resources :donations
|
||||
|
||||
get 'wallet', to: 'wallet#index'
|
||||
|
||||
get 'lnurlpay/:address', to: 'lnurlpay#index', constraints: { address: /[^\/]+/}
|
||||
get 'lnurlpay/:address/invoice', to: 'lnurlpay#invoice', constraints: { address: /[^\/]+/}
|
||||
|
||||
namespace :admin do
|
||||
root to: 'dashboard#index'
|
||||
get 'invitations', to: 'invitations#index'
|
||||
|
@ -0,0 +1,6 @@
|
||||
class AddLndhubCredentialsToUser < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
add_column :users, :ln_login_ciphertext, :text
|
||||
add_column :users, :ln_password_ciphertext, :text
|
||||
end
|
||||
end
|
@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2020_12_19_121808) do
|
||||
ActiveRecord::Schema.define(version: 2021_11_20_010540) do
|
||||
|
||||
create_table "donations", force: :cascade do |t|
|
||||
t.integer "user_id"
|
||||
@ -45,6 +45,8 @@ ActiveRecord::Schema.define(version: 2020_12_19_121808) do
|
||||
t.datetime "confirmed_at"
|
||||
t.datetime "confirmation_sent_at"
|
||||
t.string "unconfirmed_email"
|
||||
t.text "ln_login_ciphertext"
|
||||
t.text "ln_password_ciphertext"
|
||||
t.index ["email"], name: "index_users_on_email", unique: true
|
||||
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
|
||||
end
|
||||
|
8
lib/tasks/lndhub.rake
Normal file
8
lib/tasks/lndhub.rake
Normal file
@ -0,0 +1,8 @@
|
||||
namespace :lndhub do
|
||||
desc "Generate wallets for all users"
|
||||
task :generate_wallets => :environment do |t, args|
|
||||
User.all.each do |user|
|
||||
CreateLndhubWalletJob.perform_later(user)
|
||||
end
|
||||
end
|
||||
end
|
48
spec/jobs/create_lndhub_wallet_job_spec.rb
Normal file
48
spec/jobs/create_lndhub_wallet_job_spec.rb
Normal file
@ -0,0 +1,48 @@
|
||||
require 'rails_helper'
|
||||
require 'webmock/rspec'
|
||||
|
||||
RSpec.describe CreateLndhubWalletJob, type: :job do
|
||||
let(:user) { create :user, cn: "willherschel", ou: "kosmos.org" }
|
||||
|
||||
subject(:job) { described_class.perform_later(user) }
|
||||
|
||||
before do
|
||||
stub_request(:post, "http://localhost:3023/create")
|
||||
.to_return(status: 200, headers: {},
|
||||
body: { login: "abc123", password: "def456" }.to_json)
|
||||
end
|
||||
|
||||
it "creates a new LndHub account" do
|
||||
perform_enqueued_jobs { job }
|
||||
|
||||
expect(WebMock).to have_requested(:post, "http://localhost:3023/create")
|
||||
.with { |req| req.body == '{"partnerid":"kosmos.org","accounttype":"user"}' }
|
||||
|
||||
user.reload
|
||||
expect(user.ln_login).to eq("abc123")
|
||||
expect(user.ln_password).to eq("def456")
|
||||
end
|
||||
|
||||
context "with existing credentials stored" do
|
||||
before do
|
||||
user.ln_login = "foo"
|
||||
user.ln_password = "bar"
|
||||
user.save!
|
||||
end
|
||||
|
||||
it "does not create a new LndHub account" do
|
||||
perform_enqueued_jobs { job }
|
||||
|
||||
expect(WebMock).to_not have_requested(:post, "http://localhost:3023/create")
|
||||
|
||||
user.reload
|
||||
expect(user.ln_login).to eq("foo")
|
||||
expect(user.ln_password).to eq("bar")
|
||||
end
|
||||
end
|
||||
|
||||
after do
|
||||
clear_enqueued_jobs
|
||||
clear_performed_jobs
|
||||
end
|
||||
end
|
Loading…
x
Reference in New Issue
Block a user