commit bfa5219b02229e88068b4fb0a94e72d041550e56 Author: Michael Bumann Date: Mon Jan 7 01:35:26 2019 +0100 hello world diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5657f6e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +vendor \ No newline at end of file diff --git a/Gopkg.lock b/Gopkg.lock new file mode 100644 index 0000000..da6d0aa --- /dev/null +++ b/Gopkg.lock @@ -0,0 +1,285 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + digest = "1:a138d82090d405fcb3cba3d2f5858b01ad3bbd08832ffa6a6db433d9ad597575" + name = "github.com/btcsuite/btcwallet" + packages = [ + "internal/zero", + "snacl", + ] + pruneopts = "UT" + revision = "8ae4afc70174bacc745e8dd89fc6db2d817909bd" + +[[projects]] + branch = "master" + digest = "1:064d2cebe444ff7907a912c3ee249c70ae7859fd0fb03c25a0240cbcce2adb4c" + name = "github.com/btcsuite/golangcrypto" + packages = [ + "nacl/secretbox", + "pbkdf2", + "poly1305", + "salsa20/salsa", + "scrypt", + ] + pruneopts = "UT" + revision = "53f62d9b43e87a6c56975cf862af7edf33a8d0df" + +[[projects]] + digest = "1:e802928326e2d631840a238c372417c3ade751b79ff491c5f0a4755c912643cd" + name = "github.com/coreos/bbolt" + packages = ["."] + pruneopts = "UT" + revision = "4f5275f4ebbf6fe7cb772de987fa96ee674460a7" + +[[projects]] + digest = "1:76dc72490af7174349349838f2fe118996381b31ea83243812a97e5a0fd5ed55" + name = "github.com/dgrijalva/jwt-go" + packages = ["."] + pruneopts = "UT" + revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e" + version = "v3.2.0" + +[[projects]] + digest = "1:19c3d5be42d5d503b94650e45bb2a01264bb36caff20f708e9cf67a6683b4c04" + name = "github.com/golang/protobuf" + packages = [ + "jsonpb", + "proto", + "protoc-gen-go/descriptor", + "ptypes/any", + "ptypes/struct", + ] + pruneopts = "UT" + revision = "bbd03ef6da3a115852eaf24c8a1c46aeb39aa175" + +[[projects]] + digest = "1:983bdae4397d2a7c88316865e7de6b76bbedd8c33342004931829eba0975d9ed" + name = "github.com/grpc-ecosystem/grpc-gateway" + packages = [ + "runtime", + "runtime/internal", + "utilities", + ] + pruneopts = "UT" + revision = "f2862b476edcef83412c7af8687c9cd8e4097c0f" + +[[projects]] + branch = "master" + digest = "1:a330103bc9731260ee9fa14764e9e3fce46e02de19d6aca3eeba1d425badfbf0" + name = "github.com/juju/loggo" + packages = ["."] + pruneopts = "UT" + revision = "584905176618da46b895b176c721b02c476b6993" + +[[projects]] + digest = "1:9acadb9c8c15b8a9f635a7fa960c9a522b001a3919bc03df92ac26c372476aff" + name = "github.com/labstack/echo" + packages = [ + ".", + "middleware", + ] + pruneopts = "UT" + revision = "1abaa3049251d17932e4313c2d6165073fd07fd8" + version = "v3.3.6" + +[[projects]] + digest = "1:568171fc14a3d819b112c3e219d351ea7b05e8dad7935c4168c6b3373244a686" + name = "github.com/labstack/gommon" + packages = [ + "bytes", + "color", + "log", + "random", + ] + pruneopts = "UT" + revision = "2a618302b929cc20862dda3aa6f02f64dbe740dd" + version = "v0.2.7" + +[[projects]] + digest = "1:c2b45ecd1f0a0d7d3820c1c75db58ea2f5f6e89452870f1090b1afae1460c96c" + name = "github.com/lightningnetwork/lnd" + packages = [ + "lnrpc", + "macaroons", + ] + pruneopts = "UT" + revision = "fb95858afce6d7129758e7677bcb1552c5be2c51" + version = "v0.5-beta-rc2" + +[[projects]] + digest = "1:c658e84ad3916da105a761660dcaeb01e63416c8ec7bc62256a9b411a05fcd67" + name = "github.com/mattn/go-colorable" + packages = ["."] + pruneopts = "UT" + revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072" + version = "v0.0.9" + +[[projects]] + digest = "1:0981502f9816113c9c8c4ac301583841855c8cf4da8c72f696b3ebedf6d0e4e5" + name = "github.com/mattn/go-isatty" + packages = ["."] + pruneopts = "UT" + revision = "6ca4dbf54d38eea1a992b3c722a76a5d1c4cb25c" + version = "v0.0.4" + +[[projects]] + branch = "master" + digest = "1:d673e95129a1107bfd04e093751a5e1267faabc27d218d824fb013f57ac08f55" + name = "github.com/rogpeppe/fastuuid" + packages = ["."] + pruneopts = "UT" + revision = "6724a57986aff9bff1a1770e9347036def7c89f6" + +[[projects]] + digest = "1:c468422f334a6b46a19448ad59aaffdfc0a36b08fdcc1c749a0b29b6453d7e59" + name = "github.com/valyala/bytebufferpool" + packages = ["."] + pruneopts = "UT" + revision = "e746df99fe4a3986f4d4f79e13c1e0117ce9c2f7" + version = "v1.0.0" + +[[projects]] + branch = "master" + digest = "1:268b8bce0064e8c057d7b913605459f9a26dcab864c0886a56d196540fbf003f" + name = "github.com/valyala/fasttemplate" + packages = ["."] + pruneopts = "UT" + revision = "dcecefd839c4193db0d35b88ec65b4c12d360ab0" + +[[projects]] + branch = "master" + digest = "1:a57b670b0726ad104be74e5abc7b4eaea06f04a93f0fd5013d8f2a29b146753f" + name = "golang.org/x/crypto" + packages = [ + "acme", + "acme/autocert", + "curve25519", + "internal/subtle", + "nacl/box", + "nacl/secretbox", + "poly1305", + "salsa20/salsa", + ] + pruneopts = "UT" + revision = "85e1b3f9139abd58575d728a509643924e3b2ebf" + +[[projects]] + digest = "1:279284b3cc1429d8ea79402792b17c5dbfadd583ec4963db69f0368762f89be4" + name = "golang.org/x/net" + packages = [ + "context", + "http2", + "http2/hpack", + "idna", + "internal/timeseries", + "lex/httplex", + "trace", + ] + pruneopts = "UT" + revision = "ae89d30ce0c63142b652837da33d782e2b0a9b25" + +[[projects]] + branch = "master" + digest = "1:008fb9f84ae9bf7994228b9c78810d44162071ec13caf28291677897dca819ee" + name = "golang.org/x/sys" + packages = ["unix"] + pruneopts = "UT" + revision = "d989b31c87461dc8ab2f1cac6792814e27fadea9" + +[[projects]] + digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18" + name = "golang.org/x/text" + packages = [ + "collate", + "collate/build", + "internal/colltab", + "internal/gen", + "internal/tag", + "internal/triegen", + "internal/ucd", + "language", + "secure/bidirule", + "transform", + "unicode/bidi", + "unicode/cldr", + "unicode/norm", + "unicode/rangetable", + ] + pruneopts = "UT" + revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" + version = "v0.3.0" + +[[projects]] + digest = "1:c2dee8dbcc504d1a7858f5dbaed7c8b256c512c5e9e81480158c30185bbd2792" + name = "google.golang.org/genproto" + packages = [ + "googleapis/api/annotations", + "googleapis/rpc/status", + ] + pruneopts = "UT" + revision = "df60624c1e9b9d2973e889c7a1cff73155da81c4" + +[[projects]] + digest = "1:8d9ccf0a790b530f94357a5d27e9c86fb53e862b6e0f9133c792269c0b567218" + name = "google.golang.org/grpc" + packages = [ + ".", + "codes", + "connectivity", + "credentials", + "grpclb/grpc_lb_v1", + "grpclog", + "internal", + "keepalive", + "metadata", + "naming", + "peer", + "stats", + "status", + "tap", + "transport", + ] + pruneopts = "UT" + revision = "b3ddf786825de56a4178401b7e174ee332173b66" + +[[projects]] + digest = "1:9f0c81ca4b497d3723d0a66495d8a1efe277068b77ef3ad2d6460e480bf09bb3" + name = "gopkg.in/errgo.v1" + packages = ["."] + pruneopts = "UT" + revision = "b20caedf0710d0988e92b5f2d76843ad1f231f2d" + version = "v1.0.0" + +[[projects]] + digest = "1:f75654fe9e7a52c9df4c13d3c362a02e9dd0ab5e1ef336212ae68964c05ff53f" + name = "gopkg.in/macaroon-bakery.v2" + packages = [ + "bakery", + "bakery/checkers", + "bakery/internal/macaroonpb", + ] + pruneopts = "UT" + revision = "94012773d2874a067572bd16d7d11ae02968b47b" + +[[projects]] + digest = "1:0622939c131fd6ca6fc9dfb25adda2f195062975045baba7ad94607e6f3c52b7" + name = "gopkg.in/macaroon.v2" + packages = ["."] + pruneopts = "UT" + revision = "bed2a428da6e56d950bed5b41fcbae3141e5b0d0" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + input-imports = [ + "github.com/grpc-ecosystem/grpc-gateway/runtime", + "github.com/labstack/echo", + "github.com/labstack/echo/middleware", + "github.com/lightningnetwork/lnd/lnrpc", + "github.com/lightningnetwork/lnd/macaroons", + "google.golang.org/grpc", + "google.golang.org/grpc/credentials", + ] + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml new file mode 100644 index 0000000..b9e5eb0 --- /dev/null +++ b/Gopkg.toml @@ -0,0 +1,31 @@ +# Gopkg.toml example +# +# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/lightningnetwork/lnd", "google.golang.org/grpc"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + + +[prune] + go-tests = true + unused-packages = true + diff --git a/invoices.go b/invoices.go new file mode 100644 index 0000000..3a0d7c7 --- /dev/null +++ b/invoices.go @@ -0,0 +1,109 @@ +package main + +import ( + "flag" + "github.com/bumi/lntip/ln" + "github.com/labstack/echo" + "github.com/labstack/echo/middleware" + "html/template" + "io" + "io/ioutil" + "log" + "net/http" + "os" + "strconv" +) + +var stdOutLogger = log.New(os.Stdout, "", log.LstdFlags) + +type TemplateRenderer struct { + templates *template.Template +} + +func (t *TemplateRenderer) Render(w io.Writer, name string, data interface{}, c echo.Context) error { + // Add global methods if data is a map + if viewContext, isMap := data.(map[string]interface{}); isMap { + viewContext["reverse"] = c.Echo().Reverse + } + + return t.templates.ExecuteTemplate(w, name, data) +} + +func main() { + var indexView = ` + + + + + + + + + hallo + +` + + address := flag.String("address", "localhost:10009", "The host and port of the ln gRPC server") + certFile := flag.String("cert", "tls.cert", "Path to the lnd tls.cert file") + macaroonFile := flag.String("macaroon", "invoice.macaroon", "Path to the lnd macaroon file") + viewPath := flag.String("template", "", "Path of a custom HTML template file") + + flag.Parse() + + if *viewPath != "" { + content, err := ioutil.ReadFile(*viewPath) + if err != nil { + panic(err) + } + indexView = string(content) + } + + e := echo.New() + e.Static("/static", "views/assets") + e.Use(middleware.CORS()) + e.Use(middleware.Recover()) + renderer := &TemplateRenderer{ + templates: template.Must(template.New("index").Parse(indexView)), + } + e.Renderer = renderer + + lndOptions := ln.LNDoptions{ + Address: *address, + CertFile: *certFile, + MacaroonFile: *macaroonFile, + } + lnClient, err := ln.NewLNDclient(lndOptions) + if err != nil { + panic(err) + } + + e.GET("/payme", func(c echo.Context) error { + memo := c.FormValue("memo") + amount, _ := strconv.ParseInt(c.FormValue("amount"), 10, 64) + invoice, err := lnClient.GenerateInvoice(amount, memo) + if err != nil { + return c.JSON(http.StatusInternalServerError, "error") + } + + return c.JSON(http.StatusOK, invoice) + }) + + e.GET("/settled/:invoiceId", func(c echo.Context) error { + invoiceId := c.Param("invoiceId") + invoice, _ := lnClient.CheckInvoice(invoiceId) + return c.JSON(http.StatusOK, invoice) + }) + + e.GET("/", func(c echo.Context) error { + return c.Render(http.StatusOK, "index", map[string]interface{}{}) + }) + + e.Logger.Fatal(e.Start(":1323")) +} diff --git a/ln/lnd.go b/ln/lnd.go new file mode 100644 index 0000000..13d76a3 --- /dev/null +++ b/ln/lnd.go @@ -0,0 +1,149 @@ +package ln + +import ( + "context" + "encoding/hex" + "io/ioutil" + "log" + "os" + + "github.com/lightningnetwork/lnd/lnrpc" + "gopkg.in/macaroon.v2" + "github.com/lightningnetwork/lnd/macaroons" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" +) + + +var stdOutLogger = log.New(os.Stdout, "", log.LstdFlags) + +// Invoice is a Lightning Network invoice and contains the typical invoice string and the payment hash. +type Invoice struct { + ImplDepID string + PaymentHash string + PaymentRequest string +} + +type LNDclient struct { + lndClient lnrpc.LightningClient + ctx context.Context + conn *grpc.ClientConn +} + +// GenerateInvoice generates an invoice with the given price and memo. +func (c LNDclient) GenerateInvoice(amount int64, memo string) (Invoice, error) { + result := Invoice{} + + // Create the request and send it + invoice := lnrpc.Invoice{ + Memo: memo, + Value: amount, + } + stdOutLogger.Println("Creating invoice for a new API request") + res, err := c.lndClient.AddInvoice(c.ctx, &invoice) + if err != nil { + return result, err + } + + result.ImplDepID = hex.EncodeToString(res.RHash) + result.PaymentHash = result.ImplDepID + result.PaymentRequest = res.PaymentRequest + return result, nil +} + +// CheckInvoice takes an invoice ID and checks if the corresponding invoice was settled. +// An error is returned if no corresponding invoice was found. +// False is returned if the invoice isn't settled. +func (c LNDclient) CheckInvoice(id string) (bool, error) { + // In the case of lnd, the ID is the hex encoded preimage hash. + plainHash, err := hex.DecodeString(id) + if err != nil { + return false, err + } + + stdOutLogger.Printf("Checking invoice for hash %v\n", id) + + // Get the invoice for that hash + paymentHash := lnrpc.PaymentHash{ + RHash: plainHash, + // Hex encoded, must be exactly 32 byte + RHashStr: id, + } + invoice, err := c.lndClient.LookupInvoice(c.ctx, &paymentHash) + if err != nil { + return false, err + } + + // Check if invoice was settled + if !invoice.GetSettled() { + return false, nil + } + return true, nil +} + +func (c LNDclient) GetURIs() (bool, error) { + req := &lnrpc.GetInfoRequest{} + info, err := c.lndClient.GetInfo(c.ctx, req) + stdOutLogger.Println(info.Uris) + return true, err +} + + +// NewLNDclient creates a new LNDclient instance. +func NewLNDclient(lndOptions LNDoptions) (LNDclient, error) { + result := LNDclient{} + + // Set up a connection to the server. + creds, err := credentials.NewClientTLSFromFile(lndOptions.CertFile, "") + if err != nil { + return result, err + } + opts := []grpc.DialOption{ + grpc.WithTransportCredentials(creds), + } + + macaroonData, err := ioutil.ReadFile(lndOptions.MacaroonFile) + if err != nil { + return result, err + } + mac := &macaroon.Macaroon{} + if err = mac.UnmarshalBinary(macaroonData); err != nil { + return result, err + } + + macCred := macaroons.NewMacaroonCredential(mac) + opts = append(opts, grpc.WithPerRPCCredentials(macCred)) + + conn, err := grpc.Dial(lndOptions.Address, opts...) + if err != nil { + return result, err + } + + c := lnrpc.NewLightningClient(conn) + + result = LNDclient{ + conn: conn, + ctx: context.Background(), + lndClient: c, + } + + return result, nil +} + +// LNDoptions are the options for the connection to the lnd node. +type LNDoptions struct { + // Address of your LND node, including the port. + // Optional ("localhost:10009" by default). + Address string + // Path to the "tls.cert" file that your LND node uses. + // Optional ("tls.cert" by default). + CertFile string + // Path to the macaroon file that your LND node uses. + // "invoice.macaroon" if you only use the GenerateInvoice() and CheckInvoice() methods + // (required by the middleware in the package "wall"). + // "admin.macaroon" if you use the Pay() method (required by the client in the package "pay"). + // Optional ("invoice.macaroon" by default). + MacaroonFile string +} + diff --git a/views/assets/lntip.css b/views/assets/lntip.css new file mode 100644 index 0000000..0184de0 --- /dev/null +++ b/views/assets/lntip.css @@ -0,0 +1,24 @@ +@keyframes slideIn{0%{opacity:0;transform:scale(.85)}70%{opacity:1;transform:scale(1.03)}100%{transform:scale(1)}}@keyframes slideOut{from{opacity:1}to{opacity:0}}@keyframes rotate{from{transform:rotate(0)}to{transform:rotate(180deg)}}.jPopup{position:absolute;top:0;right:0;bottom:0;left:0;z-index:9999;max-width:100%;padding:50px 15px 15px;box-sizing:border-box}.jPopup:after{content:'';position:fixed;top:0;right:0;bottom:0;left:0;z-index:9998;background:#fff}.jPopup>.jCloseBtn{position:absolute;right:1rem;top:1rem;z-index:9999;outline:0;border:0;box-sizing:border-box;cursor:pointer;width:5rem;height:5rem;background:#f2f2f2;border-radius:50%}.jPopup>.jCloseBtn>.graphicIcon{width:2rem;height:2rem;position:relative;margin:0 auto}.jPopup>.jCloseBtn>.graphicIcon:after,.jPopup>.jCloseBtn>.graphicIcon:before{position:absolute;left:.9rem;content:'';height:2rem;width:.3rem;background-color:#adadad;border-radius:.5rem}.jPopup>.jCloseBtn>.graphicIcon:before{-ms-transform:rotate(45deg);transform:rotate(45deg)}.jPopup>.jCloseBtn>.graphicIcon:after{-ms-transform:rotate(-45deg);transform:rotate(-45deg)}.jPopup>.jCloseBtn:hover>.graphicIcon{animation:rotate 250ms ease-in}.jPopup>.jCloseBtn:active{-ms-transform:scale(.95);transform:scale(.95)}.jPopup>.content{top:50%;left:1.5rem;right:1.5rem;position:absolute;z-index:9999;-ms-transform:translateY(-50%);transform:translateY(-50%)}@media screen and (min-width:680px){.jPopup{padding:8rem 3rem 3rem}.jPopup>.jCloseBtn{width:6rem;height:6rem;right:2rem;top:2rem}.jPopup>.jCloseBtn:after{content:'(esc)';position:absolute;top:6.5rem;left:50%;font-size:1.1rem;-ms-transform:translateX(-50%);transform:translateX(-50%);color:#adadad;pointer-events:none}.jPopup>.jCloseBtn>.graphicIcon{width:3rem;height:3rem}.jPopup>.jCloseBtn>.graphicIcon:after,.jPopup>.jCloseBtn>.graphicIcon:before{left:1.4rem;height:3rem}.jPopup>.content{left:3rem;right:3rem}}.jPopupOpen,.jPopupOpen body{overflow:hidden}.jPopupOpen .jPopup{animation:slideIn .5s cubic-bezier(.34,.34,.26,.99)}.jPopupClosed .jPopup{animation:slideOut 250ms ease-in} + +.jPopup > .jCloseBtn { + z-index:10000; +} + +.lntip-payment-request { + width: 220px; + margin: 0 auto; + text-align: center; +} +.lntip-payment-request h1, .lntip-payment-request h2 { + text-align: center; +} + +.lntip-details { + width: 200px; + overflow: hidden; +} + +.lntip-copy { + cursor: pointer; + display: inline; +} diff --git a/views/assets/lntip.js b/views/assets/lntip.js new file mode 100644 index 0000000..96459e8 --- /dev/null +++ b/views/assets/lntip.js @@ -0,0 +1,126 @@ +/*! https://github.com/robiveli/jpopup */ +!function(e,n){void 0===e&&void 0!==window&&(e=window),"function"==typeof define&&define.amd?define([],function(){return e.jPopup=n()}):"object"==typeof module&&module.exports?module.exports=n():e.jPopup=n()}(this,function(){"use strict";var n,o,t=function(){var e=0\n \n
'.concat(e,"
\n ")))},s=function(e){1==e?window.location.hash=o:window.history.back()},d=function(e){27==e.keyCode&&t.prototype.close(!0)},c=function(){window.location.hash!==o&&t.prototype.close(!1)},a=function(){document.getElementsByClassName("jCloseBtn")[0].addEventListener("click",function(){t.prototype.close(!0)}),window.addEventListener("keydown",d),1==n&&window.addEventListener("hashchange",c)},u=document.querySelector("html");return t.prototype={close:function(e){u.classList.add("jPopupClosed"),1==n&&(e&&s(!1),window.removeEventListener("hashchange",c)),window.removeEventListener("keydown",d),document.getElementsByClassName("jPopup")[0].addEventListener("animationend",function(e){e.target.parentNode.removeChild(this),u.classList.remove("jPopupClosed"),u.classList.remove("jPopupOpen")})},open:function(e){t(e)}},t}); + +if (document.currentScript) { + window.LNTIP_HOST = document.currentScript.getAttribute('lntip-host'); +} + +LnTip = function (amount, memo, host) { + this.host = host || window.LNTIP_HOST; + this.amount = amount; + this.memo = memo || ''; + this.getInvoice(); +} + +LnTip.prototype.loadStylesheet = function () { + if (this.styleLoaded) { return } + var head = document.getElementsByTagName('head')[0]; + var css = document.createElement('link'); + css.rel = "stylesheet"; + css.type = "text/css"; + css.href = `${this.host}/static/lntip.css`; + head.appendChild(css); + this.styleLoaded = true; +} + +LnTip.prototype.closePopup = function () { + if (this.popup) { + this.popup.close(); + this.popup = null; + } +} + +LnTip.prototype.openPopup = function (content) { + this.closePopup(); + this.loadStylesheet(); + this.popup = new jPopup({ + content: content, + shouldSetHash: false + }); + return this.popup; +} + +LnTip.prototype.thanks = function () { + if (window.lntipPopup) { window.lntipPopup.close(); window.lntipPopup = null; } + var content = '

Thank you!

'; + this.openPopup(content); + setTimeout(() => { + this.closePopup(); + }, 3000); +} + +LnTip.prototype.watchPayment = function () { + if (this.paymentWatcher) { window.clearInterval(this.paymentWatcher) } + this.paymentWatcher = window.setInterval(() => { + this._request(`${this.host}/settled/${this.invoice.ImplDepID}`) + .then((settled) => { + if (settled) { + this.invoice.settled = true; + this.thanks(); + this.stopWatchingPayment(); + } + }) + }, 1000); +} + +LnTip.prototype.stopWatchingPayment = function () { + window.clearInterval(this.paymentWatcher); + this.paymentWatcher = null; +} + +LnTip.prototype.payWithWebln = function () { + if (!webln.isEnabled) { + webln.enable().then((weblnResponse) => { + return webln.sendPayment({ paymentRequest: invoice.PaymentRequest }) + }).catch((e) => { + this.requestPayment(); + }) + } else { + return webln.sendPayment({ paymentRequest: invoice.PaymentRequest }) + } +} + +LnTip.prototype.requestPayment = function () { + var content = `
+

${this.memo}

+

${this.amount} satoshi

+
+ +
+ +
` + this.openPopup(content); + + document.getElementById('lntip-copy').onclick = function() { + navigator.clipboard.writeText(invoice.PaymentRequest); + alert('Copied to clipboad'); + } + return Promise.resolve(); +} + +LnTip.prototype.getInvoice = function () { + return this._request(`${this.host}/payme?memo=${this.memo}&amount=${this.amount}`) + .then((invoice) => { + this.invoice = invoice; + this.watchPayment(); + + if (typeof webln !== 'undefined') { + this.payWithWebln(); + } else { + this.requestPayment(); + } + }) +} + +LnTip.prototype._request = function(url) { + return fetch(url).then((response) => { + return response.json(); + }) +} diff --git a/views/index.html b/views/index.html new file mode 100644 index 0000000..d6b0f4e --- /dev/null +++ b/views/index.html @@ -0,0 +1,11 @@ + + + + + + + + + + +