Merge pull request 'Add support and migration for lndhub.go' (#77) from feature/73-lndhub-go into feature/docker_compose
Reviewed-on: #77
This commit is contained in:
commit
d849d28f62
@ -1,4 +1,7 @@
|
|||||||
EJABBERD_API_URL='https://xmpp.kosmos.org:5443/api'
|
EJABBERD_API_URL='https://xmpp.kosmos.org:5443/api'
|
||||||
|
|
||||||
BTCPAY_API_URL='http://10.1.1.163:23001/api/v1'
|
BTCPAY_API_URL='http://10.1.1.163:23001/api/v1'
|
||||||
LNDHUB_API_URL='http://10.1.1.163:3023'
|
|
||||||
|
LNDHUB_LEGACY_API_URL='http://10.1.1.163:3026'
|
||||||
|
LNDHUB_API_URL='http://10.1.1.163:3026'
|
||||||
LNDHUB_PUBLIC_URL='https://lndhub.kosmos.org'
|
LNDHUB_PUBLIC_URL='https://lndhub.kosmos.org'
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
EJABBERD_API_URL='http://xmpp.example.com/api'
|
EJABBERD_API_URL='http://xmpp.example.com/api'
|
||||||
BTCPAY_API_URL='http://btcpay.example.com/api/v1'
|
BTCPAY_API_URL='http://btcpay.example.com/api/v1'
|
||||||
LNDHUB_API_URL='http://localhost:3023'
|
LNDHUB_LEGACY_API_URL='http://localhost:3023'
|
||||||
|
LNDHUB_API_URL='http://localhost:3026'
|
||||||
LNDHUB_PUBLIC_URL='https://lndhub.kosmos.org'
|
LNDHUB_PUBLIC_URL='https://lndhub.kosmos.org'
|
||||||
|
@ -28,13 +28,13 @@ class WalletController < ApplicationController
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def authenticate_with_lndhub
|
def authenticate_with_lndhub(options={})
|
||||||
if session["ln_auth_token"].present?
|
if session[:ln_auth_token].present? && !options[:force_reauth]
|
||||||
@ln_auth_token = session["ln_auth_token"]
|
@ln_auth_token = session[:ln_auth_token]
|
||||||
else
|
else
|
||||||
lndhub = Lndhub.new
|
lndhub = Lndhub.new
|
||||||
auth_token = lndhub.authenticate(current_user)
|
auth_token = lndhub.authenticate(current_user)
|
||||||
session["ln_auth_token"] = auth_token
|
session[:ln_auth_token] = auth_token
|
||||||
@ln_auth_token = auth_token
|
@ln_auth_token = auth_token
|
||||||
end
|
end
|
||||||
rescue
|
rescue
|
||||||
@ -49,14 +49,23 @@ class WalletController < ApplicationController
|
|||||||
lndhub = Lndhub.new
|
lndhub = Lndhub.new
|
||||||
data = lndhub.balance @ln_auth_token
|
data = lndhub.balance @ln_auth_token
|
||||||
@balance = data["BTC"]["AvailableBalance"] rescue nil
|
@balance = data["BTC"]["AvailableBalance"] rescue nil
|
||||||
|
rescue
|
||||||
|
authenticate_with_lndhub(force_reauth: true)
|
||||||
|
return nil if @fetch_balance_retried
|
||||||
|
@fetch_balance_retried = true
|
||||||
|
fetch_balance
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_transactions
|
def fetch_transactions
|
||||||
lndhub = Lndhub.new
|
lndhub = Lndhub.new
|
||||||
txs = lndhub.gettxs @ln_auth_token
|
txs = lndhub.gettxs @ln_auth_token
|
||||||
invoices = lndhub.getuserinvoices(@ln_auth_token).select{|i| i["ispaid"]}
|
invoices = lndhub.getuserinvoices(@ln_auth_token).select{|i| i["ispaid"]}
|
||||||
|
|
||||||
process_transactions(txs + invoices)
|
process_transactions(txs + invoices)
|
||||||
|
rescue
|
||||||
|
authenticate_with_lndhub(force_reauth: true)
|
||||||
|
return [] if @fetch_transactions_retried
|
||||||
|
@fetch_transactions_retried = true
|
||||||
|
fetch_transactions
|
||||||
end
|
end
|
||||||
|
|
||||||
def process_transactions(txs)
|
def process_transactions(txs)
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
class CreateLndhubWalletJob < ApplicationJob
|
class CreateLndhubAccountJob < ApplicationJob
|
||||||
queue_as :default
|
queue_as :default
|
||||||
|
|
||||||
def perform(user)
|
def perform(user)
|
||||||
return if user.ln_login.present? && user.ln_password.present?
|
return if user.ln_login.present? && user.ln_password.present?
|
||||||
|
|
||||||
lndhub = Lndhub.new
|
lndhub = LndhubV2.new
|
||||||
credentials = lndhub.create({ partnerid: user.ou, accounttype: "user" })
|
credentials = lndhub.create_account
|
||||||
|
|
||||||
user.update! ln_login: credentials["login"],
|
user.update! ln_login: credentials["login"],
|
||||||
ln_password: credentials["password"]
|
ln_password: credentials["password"]
|
@ -11,7 +11,7 @@ class CreateAccount < ApplicationService
|
|||||||
def call
|
def call
|
||||||
user = create_user_in_database
|
user = create_user_in_database
|
||||||
add_ldap_document
|
add_ldap_document
|
||||||
create_lndhub_wallet(user)
|
create_lndhub_account(user)
|
||||||
|
|
||||||
if @invitation.present?
|
if @invitation.present?
|
||||||
update_invitation(user.id)
|
update_invitation(user.id)
|
||||||
@ -49,9 +49,9 @@ class CreateAccount < ApplicationService
|
|||||||
ExchangeXmppContactsJob.perform_later(@invitation.user, @username, @domain)
|
ExchangeXmppContactsJob.perform_later(@invitation.user, @username, @domain)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_lndhub_wallet(user)
|
def create_lndhub_account(user)
|
||||||
#TODO enable in development when we have a local lndhub (mock?) API
|
#TODO enable in development when we have a local lndhub (mock?) API
|
||||||
return if Rails.env.development?
|
return if Rails.env.development?
|
||||||
CreateLndhubWalletJob.perform_later(user)
|
CreateLndhubAccountJob.perform_later(user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2,7 +2,7 @@ class Lndhub
|
|||||||
attr_accessor :auth_token
|
attr_accessor :auth_token
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@base_url = ENV["LNDHUB_API_URL"]
|
@base_url = ENV["LNDHUB_LEGACY_API_URL"]
|
||||||
end
|
end
|
||||||
|
|
||||||
def post(endpoint, payload)
|
def post(endpoint, payload)
|
||||||
@ -28,8 +28,13 @@ class Lndhub
|
|||||||
"Accept" => "application/json",
|
"Accept" => "application/json",
|
||||||
"Authorization" => "Bearer #{auth_token}"
|
"Authorization" => "Bearer #{auth_token}"
|
||||||
})
|
})
|
||||||
|
data = JSON.parse(res.body)
|
||||||
|
|
||||||
JSON.parse(res.body)
|
if data.is_a?(Hash) && data["error"] && data["message"] == "bad auth"
|
||||||
|
raise "BAD_AUTH"
|
||||||
|
else
|
||||||
|
data
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def create(payload)
|
def create(payload)
|
||||||
@ -42,15 +47,15 @@ class Lndhub
|
|||||||
self.auth_token
|
self.auth_token
|
||||||
end
|
end
|
||||||
|
|
||||||
def balance(user_token)
|
def balance(user_token=nil)
|
||||||
get "balance", user_token || auth_token
|
get "balance", user_token || auth_token
|
||||||
end
|
end
|
||||||
|
|
||||||
def gettxs(user_token)
|
def gettxs(user_token=nil)
|
||||||
get "gettxs", user_token || auth_token
|
get "gettxs", user_token || auth_token
|
||||||
end
|
end
|
||||||
|
|
||||||
def getuserinvoices(user_token)
|
def getuserinvoices(user_token=nil)
|
||||||
get "getuserinvoices", user_token || auth_token
|
get "getuserinvoices", user_token || auth_token
|
||||||
end
|
end
|
||||||
|
|
||||||
|
81
app/services/lndhub_v2.rb
Normal file
81
app/services/lndhub_v2.rb
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
class LndhubV2
|
||||||
|
attr_accessor :auth_token
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@base_url = ENV["LNDHUB_API_URL"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def post(endpoint, payload, options={})
|
||||||
|
headers = { "Content-Type" => "application/json" }
|
||||||
|
if auth_token
|
||||||
|
headers.merge!({ "Authorization" => "Bearer #{auth_token}" })
|
||||||
|
elsif options[:admin_token]
|
||||||
|
headers.merge!({ "Authorization" => "Bearer #{options[:admin_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=nil)
|
||||||
|
get "balance", user_token || auth_token
|
||||||
|
end
|
||||||
|
|
||||||
|
def gettxs(user_token)
|
||||||
|
get "gettxs", user_token || auth_token
|
||||||
|
end
|
||||||
|
|
||||||
|
def getuserinvoices(user_token)
|
||||||
|
get "getuserinvoices", user_token || auth_token
|
||||||
|
end
|
||||||
|
|
||||||
|
def addinvoice(payload)
|
||||||
|
invoice = post "addinvoice", {
|
||||||
|
amt: payload[:amount],
|
||||||
|
memo: payload[:memo],
|
||||||
|
description_hash: payload[:description_hash]
|
||||||
|
}
|
||||||
|
|
||||||
|
invoice["payment_request"]
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# V2
|
||||||
|
#
|
||||||
|
|
||||||
|
def create_account(payload={})
|
||||||
|
post "v2/users", payload, admin_token: Rails.application.credentials.lndhub[:admin_token]
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_invoice(payload)
|
||||||
|
# Payload: { amount: 1000, description: "", description_hash: "" }
|
||||||
|
post "v2/invoices", payload
|
||||||
|
end
|
||||||
|
end
|
@ -1 +1 @@
|
|||||||
oDf4FcihlyfHQuf9SUwfr+UVA0kXoECtHV3vEwtBp2TktCWkWz7SPbSZ2cLT0+EknOKhuI9xutrs311YDU2EzqZba4fZ0+a6/ohVH4jUbk1XfiHZWBp4zh+9TZ5m5Tp2RxcXpdcWPY38mP4zHWFzobTOR/brLjuemozvh8MiBSPY4NN5NR6rbFo87auK6fvYO8ik/1Qwf6pQMoVDjcTh2983po1RU/gSevUmaYsmTTHcQ5T9O9wMIBc101iZyKhkAZG46a6eNYok8yqRm18AHWr+De2j7LlBaqYSz/BZA385RWhhqoeONArwyo3Az30Bv74VttUSJAPurkRg2wDF9t8A+cvf8CeYkZ6u398JLSJbZZ6YdQS5T4IcrnONRXtp3d/m+yw+XEzpluK3MvFbV02AhZk/xzkGK6xonhaTSh1ek9hXoYrUTBzu8HBzXwKjJMnvrAodldu++/rMwLsgVmFHqXC3dydVogatLev8z6ziuGkmeMAR1d9kzGBHM3FWgsWLD7j0Ug7MTMyNWioI3r6J2QTnxkyJGh3pKBlq8Fb/Q0ypERxOfSZVQQh2gB79RMEDIemdCmN5mCU3ojsxqAAip4v9C1BZMWPtom1sHLYQSd9Bh6i0nncrNEtZXcxe5Z8JCWQolHvvfoIF2rfJh2oXYLxNx5n/1fzaoSqBdLBgvsAMA0ZWfV1wa/5V/DCa9vaJjumzHYKcfCCYbVz9PjN9OUSfwrE3nWZu8Y0awsNgmeRQwI10j2+oYYSBp040I05Vj5FM7nCgHLpdupctwaH2/VlIq83OVI6VlbzxYEay7+R5ANmpiJ+vC466DzLv8LAeFOqh/XeNeOITUm9EzhGSgf98yuDc7vsi3gmc2g7atgQ3gpSje6vEfhigm3ukydaGfA==--IYQBMD+Tar1g+srm--01E5mujYFWvcpT8Qd9HxiA==
|
yEs5CyuAbqphlDWgtw/YQvkPn+EN4ecen2dAjs7zvYErkRRWp99FinGlQIMe6NRkMLLLSIj2BwR/wlscn1kLpIfwGpxfSZ89srK3do6Mb5QogpxdUsnQB8qv5PTGRQFBcjM47s1Q5m0t+OKxGvOnLyKnQp+cVS2KFJMbSzQarW8wIZSz2gKArn9Ttk0kqUHMlJWNY7Yh6xIrrxlEalaTOVzPdtnF7u8Tobminu15eeWHMormMRz4dYSaDc6hUtfpdy1NzOHaeXIU9A9RY/iytxuIQNgcMAlcWbPe//rVk/unH2F8xqSOfed4h/nC08F/qq4z8va3kEXBSdW/G91aIDMu1mo0kX3YNibq8s25C/CfGpzw39ozJ9erTBH7hy6nfmxU6qZuWcTGDj3NOfKe/XIfDcpOjsqkT2IOFARrYodb67q23IuOufraK1/FD4LXu8l0S8/Oi0cqMjtPPs7tS0M1C3DrbmlEzGKETrHpmoKHqjA0rgOmK4ZZM9LeI+l8Z+fDpYcCak9fLGGxnjf+nKiYMSUtm9+1dwycG2lpBV6fbmIKHJWngO2jVGcycODkc525oUaAO4hdPMqrz1AdU3AzYmLJTxW3aZ4uL5NyEJ7TbUBC0HT7h2gEi/tUry4cfD2EsM9bCrCUNuMBrnPqd4r8AvORoqqYIw1IEsP0RgWa2+hfeG1QCjBRPFHQOcqo+W25CelivMe79qI08w0iC8S4hfOQO4QrmMgtd1BhcR+wVpVE3X9EJZi3Hl7z14hXcSic+gkswJMtVZcnJL4rmZ0iEW1mpqUuegsX5vB/4qPxiQyeB80pg8Q33shvUbixzSBkl6znmLSiIffsiDsGOsnuzfl/MUT+JBs3UswNt4tSp7nEwhUjKFHrZHrAJiGCdtIS6yDPGe3HfQv1JkQ+9A8zv88hRmzeIx2JyT/shtIqGo+4ZTJd5cma--Lij/n0+cpstyZD28--FOUhwW3y+0jdaYkKvG2xrg==
|
@ -1 +1 @@
|
|||||||
IIjYiPSeZeMFhH8i8v8akXN4JrtGU+OsMQ8GAao/gVdesggriCBAQ8z+Vd0cmTf1SKYeT3OQDgygEekupr325P4eD9fZ+yi56EA/UMXQXMDVZAvZw7iwvKaOXpqisbWdJnomr1GXrHyR415Ce/Fxft3fgXDwMHJW2u+dDJgpE09uORnB9GXycFwHQmoIdXo=--iQ/Vcm0VcwHgUkwQ--tKHQW/45gM/s/NplqGPaxw==
|
vqH5By5qFLImVjdlWj+7FwGg8APKnr/AEd7WqekG7L0vNA32WGBpwS1uGzs02LIcATRwGj8DyJxiBOB/w9z8cwoO+t6Woi5hAnOSCQwFWKLT0dZq7jgtT8pxK0Yu/Nf91PEFN1rc/8ZFy2KKVpbtMbMPyivT38e/ctBZD/lHrWkndvLXYvFVhqWjUnDOGbhwl/U0RZgqBBjvlm3B0JkQfiN8VXPlCJL2Cd8kd0+MpRCRTgtcxA==--OdVXnDP7OhzJxCsP--+8SI6IFIeXyDxXb+WpqhIQ==
|
@ -21,4 +21,31 @@ namespace :lndhub do
|
|||||||
end
|
end
|
||||||
puts "--\nSum of user balances: #{sum} sats"
|
puts "--\nSum of user balances: #{sum} sats"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc "Migrate existing accounts to lndhub.go"
|
||||||
|
task :migrate => :environment do |t, args|
|
||||||
|
# user = User.find_by cn: "jimmy"
|
||||||
|
User.all.each do |user|
|
||||||
|
puts "Migrating #{user.cn}"
|
||||||
|
puts "Creating account..."
|
||||||
|
lndhub_v2 = LndhubV2.new
|
||||||
|
res = lndhub_v2.create_account login: user.ln_login, password: user.ln_password
|
||||||
|
puts res.inspect
|
||||||
|
|
||||||
|
lndhub = Lndhub.new
|
||||||
|
lndhub.authenticate(user)
|
||||||
|
data = lndhub.balance
|
||||||
|
balance = data["BTC"]["AvailableBalance"] rescue 0
|
||||||
|
|
||||||
|
if balance > 0
|
||||||
|
lndhub_v2.authenticate(user)
|
||||||
|
desc = "Balance migration from old Kosmos Lightning back-end"
|
||||||
|
res = lndhub_v2.create_invoice amount: balance, description: desc
|
||||||
|
puts "Payment request for #{user.cn} (#{balance} sats):"
|
||||||
|
puts res["payment_request"]
|
||||||
|
end
|
||||||
|
|
||||||
|
puts "---"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
require 'webmock/rspec'
|
require 'webmock/rspec'
|
||||||
|
|
||||||
RSpec.describe CreateLndhubWalletJob, type: :job do
|
RSpec.describe CreateLndhubAccountJob, type: :job do
|
||||||
let(:user) { create :user, cn: "willherschel", ou: "kosmos.org" }
|
let(:user) { create :user, cn: "willherschel", ou: "kosmos.org" }
|
||||||
|
|
||||||
subject(:job) { described_class.perform_later(user) }
|
subject(:job) { described_class.perform_later(user) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_request(:post, "http://localhost:3023/create")
|
stub_request(:post, "http://localhost:3026/v2/users")
|
||||||
.to_return(status: 200, headers: {},
|
.to_return(status: 200, headers: {},
|
||||||
body: { login: "abc123", password: "def456" }.to_json)
|
body: { login: "abc123", password: "def456" }.to_json)
|
||||||
end
|
end
|
||||||
@ -15,8 +15,8 @@ RSpec.describe CreateLndhubWalletJob, type: :job do
|
|||||||
it "creates a new LndHub account" do
|
it "creates a new LndHub account" do
|
||||||
perform_enqueued_jobs { job }
|
perform_enqueued_jobs { job }
|
||||||
|
|
||||||
expect(WebMock).to have_requested(:post, "http://localhost:3023/create")
|
expect(WebMock).to have_requested(:post, "http://localhost:3026/v2/users")
|
||||||
.with { |req| req.body == '{"partnerid":"kosmos.org","accounttype":"user"}' }
|
.with { |req| req.body == '{}' }
|
||||||
|
|
||||||
user.reload
|
user.reload
|
||||||
expect(user.ln_login).to eq("abc123")
|
expect(user.ln_login).to eq("abc123")
|
@ -93,7 +93,7 @@ RSpec.describe CreateAccount, type: :model do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#create_lndhub_wallet" do
|
describe "#create_lndhub_account" do
|
||||||
include ActiveJob::TestHelper
|
include ActiveJob::TestHelper
|
||||||
|
|
||||||
let(:service) { CreateAccount.new(
|
let(:service) { CreateAccount.new(
|
||||||
@ -102,8 +102,8 @@ RSpec.describe CreateAccount, type: :model do
|
|||||||
)}
|
)}
|
||||||
let(:new_user) { create :user, cn: "halfinney", ou: "kosmos.org" }
|
let(:new_user) { create :user, cn: "halfinney", ou: "kosmos.org" }
|
||||||
|
|
||||||
it "enqueues a job to create an LndHub wallet" do
|
it "enqueues a job to create an LndHub account" do
|
||||||
service.send(:create_lndhub_wallet, new_user)
|
service.send(:create_lndhub_account, new_user)
|
||||||
|
|
||||||
expect(enqueued_jobs.size).to eq(1)
|
expect(enqueued_jobs.size).to eq(1)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user