Release v2.2.0

This commit is contained in:
Santiago Lezica
2021-11-12 19:06:13 -03:00
parent 64a820d429
commit 58d843ad79
249 changed files with 73797 additions and 1145 deletions

21
vendor/github.com/fiatjaf/go-lnurl/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 fiatjaf
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

6
vendor/github.com/fiatjaf/go-lnurl/README.md generated vendored Normal file
View File

@@ -0,0 +1,6 @@
lnurl
=====
A bunch of helpers for building [lnurl](https://telegra.ph/lnurl-a-protocol-for-seamless-interaction-between-services-and-Lightning-wallets-08-19) support into services.
See [GoDoc](https://godoc.org/github.com/fiatjaf/go-lnurl).

48
vendor/github.com/fiatjaf/go-lnurl/aes.go generated vendored Normal file
View File

@@ -0,0 +1,48 @@
package lnurl
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"io"
)
func AESCipher(key, plaintext []byte) (ciphertext []byte, iv []byte, err error) {
pad := aes.BlockSize - (len(plaintext) % aes.BlockSize)
padding := make([]byte, pad)
for i := 0; i < pad; i++ {
padding[i] = byte(pad)
}
plaintext = append(plaintext, padding...)
block, err := aes.NewCipher(key)
if err != nil {
return
}
ciphertext = make([]byte, len(plaintext))
iv = make([]byte, aes.BlockSize)
if _, err = io.ReadFull(rand.Reader, iv); err != nil {
return
}
cbc := cipher.NewCBCEncrypter(block, iv)
cbc.CryptBlocks(ciphertext, plaintext)
return
}
func AESDecipher(key, ciphertext, iv []byte) (plaintext []byte, err error) {
block, err := aes.NewCipher(key)
if err != nil {
return
}
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(ciphertext, ciphertext)
size := len(ciphertext)
pad := ciphertext[size-1]
plaintext = ciphertext[:size-int(pad)]
return plaintext, nil
}

55
vendor/github.com/fiatjaf/go-lnurl/auth.go generated vendored Normal file
View File

@@ -0,0 +1,55 @@
package lnurl
import (
"encoding/hex"
"errors"
"net/url"
"github.com/btcsuite/btcd/btcec"
)
type LNURLAuthParams struct {
Tag string
K1 string
Callback string
Host string
}
func (_ LNURLAuthParams) LNURLKind() string { return "lnurl-auth" }
// VerifySignature takes the hex-encoded parameters passed to an lnurl-login endpoint and verifies
// the signature against the key and challenge.
func VerifySignature(k1, sig, key string) (ok bool, err error) {
bk1, err1 := hex.DecodeString(k1)
bsig, err2 := hex.DecodeString(sig)
bkey, err3 := hex.DecodeString(key)
if err1 != nil || err2 != nil || err3 != nil {
return false, errors.New("Failed to decode hex.")
}
pubkey, err := btcec.ParsePubKey(bkey, btcec.S256())
if err != nil {
return false, errors.New("Failed to parse pubkey: " + err.Error())
}
signature, err := btcec.ParseDERSignature(bsig, btcec.S256())
if err != nil {
return false, errors.New("Failed to parse signature: " + err.Error())
}
return signature.Verify(bk1, pubkey), nil
}
func HandleAuth(rawurl string, parsed *url.URL, query url.Values) (LNURLParams, error) {
k1 := query.Get("k1")
if _, err := hex.DecodeString(k1); err != nil || len(k1) != 64 {
return nil, errors.New("k1 is not a valid 32-byte hex-encoded string.")
}
return LNURLAuthParams{
Tag: "login",
K1: k1,
Callback: rawurl,
Host: parsed.Host,
}, nil
}

37
vendor/github.com/fiatjaf/go-lnurl/base.go generated vendored Normal file
View File

@@ -0,0 +1,37 @@
package lnurl
import (
"net/url"
)
// The base response for all lnurl calls.
type LNURLResponse struct {
Status string `json:"status,omitempty"`
Reason string `json:"reason,omitempty"`
}
type LNURLErrorResponse struct {
Status string `json:"status,omitempty"`
Reason string `json:"reason,omitempty"`
URL *url.URL `json:"-"`
}
func (r LNURLErrorResponse) Error() string {
return r.Reason
}
func OkResponse() LNURLResponse {
return LNURLResponse{Status: "OK"}
}
func ErrorResponse(reason string) LNURLErrorResponse {
return LNURLErrorResponse{
URL: nil,
Status: "ERROR",
Reason: reason,
}
}
type LNURLParams interface {
LNURLKind() string
}

241
vendor/github.com/fiatjaf/go-lnurl/bech32.go generated vendored Normal file
View File

@@ -0,0 +1,241 @@
package lnurl
import (
"fmt"
"strings"
)
const charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
var gen = []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3}
// Decode decodes a bech32 encoded string, returning the human-readable
// part and the data part excluding the checksum.
func Decode(bech string) (string, []byte, error) {
// Only ASCII characters between 33 and 126 are allowed.
for i := 0; i < len(bech); i++ {
if bech[i] < 33 || bech[i] > 126 {
return "", nil, fmt.Errorf("invalid character in "+
"string: '%c'", bech[i])
}
}
// The characters must be either all lowercase or all uppercase.
lower := strings.ToLower(bech)
upper := strings.ToUpper(bech)
if bech != lower && bech != upper {
return "", nil, fmt.Errorf("string not all lowercase or all " +
"uppercase")
}
// We'll work with the lowercase string from now on.
bech = lower
// The string is invalid if the last '1' is non-existent, it is the
// first character of the string (no human-readable part) or one of the
// last 6 characters of the string (since checksum cannot contain '1'),
// or if the string is more than 90 characters in total.
one := strings.LastIndexByte(bech, '1')
if one < 1 || one+7 > len(bech) {
return "", nil, fmt.Errorf("invalid index of 1")
}
// The human-readable part is everything before the last '1'.
hrp := bech[:one]
data := bech[one+1:]
// Each character corresponds to the byte with value of the index in
// 'charset'.
decoded, err := toBytes(data)
if err != nil {
return "", nil, fmt.Errorf("failed converting data to bytes: "+
"%v", err)
}
if !bech32VerifyChecksum(hrp, decoded) {
moreInfo := ""
checksum := bech[len(bech)-6:]
expected, err := toChars(bech32Checksum(hrp,
decoded[:len(decoded)-6]))
if err == nil {
moreInfo = fmt.Sprintf("Expected %v, got %v.",
expected, checksum)
}
return "", nil, fmt.Errorf("checksum failed. " + moreInfo)
}
// We exclude the last 6 bytes, which is the checksum.
return hrp, decoded[:len(decoded)-6], nil
}
// Encode encodes a byte slice into a bech32 string with the
// human-readable part hrb. Note that the bytes must each encode 5 bits
// (base32).
func Encode(hrp string, data []byte) (string, error) {
// Calculate the checksum of the data and append it at the end.
checksum := bech32Checksum(hrp, data)
combined := append(data, checksum...)
// The resulting bech32 string is the concatenation of the hrp, the
// separator 1, data and checksum. Everything after the separator is
// represented using the specified charset.
dataChars, err := toChars(combined)
if err != nil {
return "", fmt.Errorf("unable to convert data bytes to chars: "+
"%v", err)
}
return hrp + "1" + dataChars, nil
}
// toBytes converts each character in the string 'chars' to the value of the
// index of the correspoding character in 'charset'.
func toBytes(chars string) ([]byte, error) {
decoded := make([]byte, 0, len(chars))
for i := 0; i < len(chars); i++ {
index := strings.IndexByte(charset, chars[i])
if index < 0 {
return nil, fmt.Errorf("invalid character not part of "+
"charset: %v", chars[i])
}
decoded = append(decoded, byte(index))
}
return decoded, nil
}
// toChars converts the byte slice 'data' to a string where each byte in 'data'
// encodes the index of a character in 'charset'.
func toChars(data []byte) (string, error) {
result := make([]byte, 0, len(data))
for _, b := range data {
if int(b) >= len(charset) {
return "", fmt.Errorf("invalid data byte: %v", b)
}
result = append(result, charset[b])
}
return string(result), nil
}
// ConvertBits converts a byte slice where each byte is encoding fromBits bits,
// to a byte slice where each byte is encoding toBits bits.
func ConvertBits(data []byte, fromBits, toBits uint8, pad bool) ([]byte, error) {
if fromBits < 1 || fromBits > 8 || toBits < 1 || toBits > 8 {
return nil, fmt.Errorf("only bit groups between 1 and 8 allowed")
}
// The final bytes, each byte encoding toBits bits.
var regrouped []byte
// Keep track of the next byte we create and how many bits we have
// added to it out of the toBits goal.
nextByte := byte(0)
filledBits := uint8(0)
for _, b := range data {
// Discard unused bits.
b = b << (8 - fromBits)
// How many bits remaining to extract from the input data.
remFromBits := fromBits
for remFromBits > 0 {
// How many bits remaining to be added to the next byte.
remToBits := toBits - filledBits
// The number of bytes to next extract is the minimum of
// remFromBits and remToBits.
toExtract := remFromBits
if remToBits < toExtract {
toExtract = remToBits
}
// Add the next bits to nextByte, shifting the already
// added bits to the left.
nextByte = (nextByte << toExtract) | (b >> (8 - toExtract))
// Discard the bits we just extracted and get ready for
// next iteration.
b = b << toExtract
remFromBits -= toExtract
filledBits += toExtract
// If the nextByte is completely filled, we add it to
// our regrouped bytes and start on the next byte.
if filledBits == toBits {
regrouped = append(regrouped, nextByte)
filledBits = 0
nextByte = 0
}
}
}
// We pad any unfinished group if specified.
if pad && filledBits > 0 {
nextByte = nextByte << (toBits - filledBits)
regrouped = append(regrouped, nextByte)
filledBits = 0
nextByte = 0
}
// Any incomplete group must be <= 4 bits, and all zeroes.
if filledBits > 0 && (filledBits > 4 || nextByte != 0) {
return nil, fmt.Errorf("invalid incomplete group")
}
return regrouped, nil
}
// For more details on the checksum calculation, please refer to BIP 173.
func bech32Checksum(hrp string, data []byte) []byte {
// Convert the bytes to list of integers, as this is needed for the
// checksum calculation.
integers := make([]int, len(data))
for i, b := range data {
integers[i] = int(b)
}
values := append(bech32HrpExpand(hrp), integers...)
values = append(values, []int{0, 0, 0, 0, 0, 0}...)
polymod := bech32Polymod(values) ^ 1
var res []byte
for i := 0; i < 6; i++ {
res = append(res, byte((polymod>>uint(5*(5-i)))&31))
}
return res
}
// For more details on the polymod calculation, please refer to BIP 173.
func bech32Polymod(values []int) int {
chk := 1
for _, v := range values {
b := chk >> 25
chk = (chk&0x1ffffff)<<5 ^ v
for i := 0; i < 5; i++ {
if (b>>uint(i))&1 == 1 {
chk ^= gen[i]
}
}
}
return chk
}
// For more details on HRP expansion, please refer to BIP 173.
func bech32HrpExpand(hrp string) []int {
v := make([]int, 0, len(hrp)*2+1)
for i := 0; i < len(hrp); i++ {
v = append(v, int(hrp[i]>>5))
}
v = append(v, 0)
for i := 0; i < len(hrp); i++ {
v = append(v, int(hrp[i]&31))
}
return v
}
// For more details on the checksum verification, please refer to BIP 173.
func bech32VerifyChecksum(hrp string, data []byte) bool {
integers := make([]int, len(data))
for i, b := range data {
integers[i] = int(b)
}
concat := append(bech32HrpExpand(hrp), integers...)
return bech32Polymod(concat) == 1
}

39
vendor/github.com/fiatjaf/go-lnurl/channel.go generated vendored Normal file
View File

@@ -0,0 +1,39 @@
package lnurl
import (
"errors"
"net/url"
"github.com/tidwall/gjson"
)
type LNURLChannelResponse struct {
LNURLResponse
Tag string `json:"tag"`
K1 string `json:"k1"`
Callback string `json:"callback"`
CallbackURL *url.URL `json:"-"`
URI string `json:"uri"`
}
func (_ LNURLChannelResponse) LNURLKind() string { return "lnurl-channel" }
func HandleChannel(j gjson.Result) (LNURLParams, error) {
k1 := j.Get("k1").String()
if k1 == "" {
return nil, errors.New("k1 is blank")
}
callback := j.Get("callback").String()
callbackURL, err := url.Parse(callback)
if err != nil {
return nil, errors.New("callback is not a valid URL")
}
return LNURLChannelResponse{
Tag: "channelRequest",
K1: k1,
Callback: callback,
CallbackURL: callbackURL,
URI: j.Get("uri").String(),
}, nil
}

39
vendor/github.com/fiatjaf/go-lnurl/codec.go generated vendored Normal file
View File

@@ -0,0 +1,39 @@
package lnurl
import (
"errors"
"strings"
)
// LNURLDecode takes a bech32-encoded lnurl string and returns a plain-text https URL.
func LNURLDecode(lnurl string) (url string, err error) {
tag, data, err := Decode(lnurl)
if err != nil {
return
}
if tag != "lnurl" {
err = errors.New("tag is not 'lnurl', but '" + tag + "'")
return
}
converted, err := ConvertBits(data, 5, 8, false)
if err != nil {
return
}
url = string(converted)
return
}
// LNURLEncode takes a plain-text https URL and returns a bech32-encoded uppercased lnurl string.
func LNURLEncode(actualurl string) (lnurl string, err error) {
asbytes := []byte(actualurl)
converted, err := ConvertBits(asbytes, 8, 5, true)
if err != nil {
return
}
lnurl, err = Encode("lnurl", converted)
return strings.ToUpper(lnurl), err
}

8
vendor/github.com/fiatjaf/go-lnurl/go.mod generated vendored Normal file
View File

@@ -0,0 +1,8 @@
module github.com/fiatjaf/go-lnurl
go 1.14
require (
github.com/btcsuite/btcd v0.20.1-beta
github.com/tidwall/gjson v1.6.0
)

35
vendor/github.com/fiatjaf/go-lnurl/go.sum generated vendored Normal file
View File

@@ -0,0 +1,35 @@
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/tidwall/gjson v1.6.0 h1:9VEQWz6LLMUsUl6PueE49ir4Ka6CzLymOAZDxpFsTDc=
github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

83
vendor/github.com/fiatjaf/go-lnurl/handle.go generated vendored Normal file
View File

@@ -0,0 +1,83 @@
package lnurl
import (
"errors"
"io/ioutil"
"net/http"
"net/url"
"strings"
"github.com/tidwall/gjson"
)
// HandleLNURL takes a bech32-encoded lnurl and either gets its parameters from the query-
// string or calls the URL to get the parameters.
// Returns a different struct for each of the lnurl subprotocols, the .LNURLKind() method of
// which should be checked next to see how the wallet is going to proceed.
func HandleLNURL(rawlnurl string) (string, LNURLParams, error) {
var err error
var rawurl string
if strings.HasPrefix(rawlnurl, "https:") {
rawurl = rawlnurl
} else {
lnurl, ok := FindLNURLInText(rawlnurl)
if !ok {
return "", nil, errors.New("invalid bech32-encoded lnurl: " + rawlnurl)
}
rawurl, err = LNURLDecode(lnurl)
if err != nil {
return "", nil, err
}
}
parsed, err := url.Parse(rawurl)
if err != nil {
return rawurl, nil, err
}
query := parsed.Query()
switch query.Get("tag") {
case "login":
value, err := HandleAuth(rawurl, parsed, query)
return rawurl, value, err
case "withdrawRequest":
if value, ok := HandleFastWithdraw(query); ok {
return rawurl, value, nil
}
}
resp, err := http.Get(rawurl)
if err != nil {
return rawurl, nil, err
}
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return rawurl, nil, err
}
j := gjson.ParseBytes(b)
if j.Get("status").String() == "ERROR" {
return rawurl, nil, LNURLErrorResponse{
URL: parsed,
Reason: j.Get("reason").String(),
Status: "ERROR",
}
}
switch j.Get("tag").String() {
case "withdrawRequest":
value, err := HandleWithdraw(j)
return rawurl, value, err
case "payRequest":
value, err := HandlePay(j)
return rawurl, value, err
case "channelRequest":
value, err := HandleChannel(j)
return rawurl, value, err
default:
return rawurl, nil, errors.New("unknown response tag " + j.String())
}
}

29
vendor/github.com/fiatjaf/go-lnurl/helpers.go generated vendored Normal file
View File

@@ -0,0 +1,29 @@
package lnurl
import (
"crypto/rand"
"encoding/hex"
"regexp"
"strings"
)
var lnurlregex = regexp.MustCompile(`.*?((lnurl)([0-9]{1,}[a-z0-9]+){1})`)
// FindLNURLInText uses a Regular Expression to find a bech32-encoded lnurl string in a blob of text.
func FindLNURLInText(text string) (lnurl string, ok bool) {
text = strings.ToLower(text)
results := lnurlregex.FindStringSubmatch(text)
if len(results) == 0 {
return
}
return results[1], true
}
// RandomK1 returns a 32-byte random hex-encoded string for usage as k1 in lnurl-auth and anywhere else.
func RandomK1() string {
random := make([]byte, 32)
rand.Read(random)
return hex.EncodeToString(random)
}

202
vendor/github.com/fiatjaf/go-lnurl/pay.go generated vendored Normal file
View File

@@ -0,0 +1,202 @@
package lnurl
import (
"encoding/base64"
"encoding/json"
"errors"
"net/url"
"strconv"
"strings"
"time"
"github.com/tidwall/gjson"
)
var (
f bool = false
t bool = true
FALSE *bool = &f
TRUE *bool = &t
)
func Action(text string, url string) *SuccessAction {
if url == "" {
return &SuccessAction{
Tag: "message",
Message: text,
}
}
if text == "" {
text = " "
}
return &SuccessAction{
Tag: "url",
Description: text,
URL: url,
}
}
func AESAction(description string, preimage []byte, content string) (*SuccessAction, error) {
plaintext := []byte(content)
ciphertext, iv, err := AESCipher(preimage, plaintext)
if err != nil {
return nil, err
}
return &SuccessAction{
Tag: "aes",
Description: description,
Ciphertext: base64.StdEncoding.EncodeToString(ciphertext),
IV: base64.StdEncoding.EncodeToString(iv),
}, nil
}
type LNURLPayResponse1 struct {
LNURLResponse
Callback string `json:"callback"`
CallbackURL *url.URL `json:"-"`
Tag string `json:"tag"`
MaxSendable int64 `json:"maxSendable"`
MinSendable int64 `json:"minSendable"`
EncodedMetadata string `json:"metadata"`
Metadata Metadata `json:"-"`
CommentAllowed int64 `json:"commentAllowed"`
}
type LNURLPayResponse2 struct {
LNURLResponse
SuccessAction *SuccessAction `json:"successAction"`
Routes [][]RouteInfo `json:"routes"`
PR string `json:"pr"`
Disposable *bool `json:"disposable,omitempty"`
}
type RouteInfo struct {
NodeId string `json:"nodeId"`
ChannelUpdate string `json:"channelUpdate"`
}
type SuccessAction struct {
Tag string `json:"tag"`
Description string `json:"description,omitempty"`
URL string `json:"url,omitempty"`
Message string `json:"message,omitempty"`
Ciphertext string `json:"ciphertext,omitempty"`
IV string `json:"iv,omitempty"`
}
func (sa *SuccessAction) Decipher(preimage []byte) (content string, err error) {
ciphertext, err := base64.StdEncoding.DecodeString(sa.Ciphertext)
if err != nil {
return
}
iv, err := base64.StdEncoding.DecodeString(sa.IV)
if err != nil {
return
}
plaintext, err := AESDecipher(preimage, ciphertext, iv)
if err != nil {
return
}
return string(plaintext), nil
}
func (_ LNURLPayResponse1) LNURLKind() string { return "lnurl-pay" }
func HandlePay(j gjson.Result) (LNURLParams, error) {
strmetadata := j.Get("metadata").String()
var metadata Metadata
err := json.Unmarshal([]byte(strmetadata), &metadata)
if err != nil {
return nil, err
}
callback := j.Get("callback").String()
// parse url
callbackURL, err := url.Parse(callback)
if err != nil {
return nil, errors.New("callback is not a valid URL")
}
// add random nonce to avoid caches
qs := callbackURL.Query()
qs.Set("nonce", strconv.FormatInt(time.Now().Unix(), 10))
callbackURL.RawQuery = qs.Encode()
return LNURLPayResponse1{
Tag: "payRequest",
Callback: callback,
CallbackURL: callbackURL,
EncodedMetadata: strmetadata,
Metadata: metadata,
MaxSendable: j.Get("maxSendable").Int(),
MinSendable: j.Get("minSendable").Int(),
CommentAllowed: j.Get("commentAllowed").Int(),
}, nil
}
type Metadata [][]string
// Description returns the content of text/plain metadata entry.
func (m Metadata) Description() string {
for _, entry := range m {
if len(entry) == 2 && entry[0] == "text/plain" {
return entry[1]
}
}
return ""
}
// ImageDataURI returns image in the form data:image/type;base64,... if an image exists
// or an empty string if not.
func (m Metadata) ImageDataURI() string {
for _, entry := range m {
if len(entry) == 2 && strings.Split(entry[0], "/")[0] == "image" {
return "data:" + entry[0] + "," + entry[1]
}
}
return ""
}
// ImageBytes returns image as bytes, decoded from base64 if an image exists
// or nil if not.
func (m Metadata) ImageBytes() []byte {
for _, entry := range m {
if len(entry) == 2 && strings.Split(entry[0], "/")[0] == "image" {
if decoded, err := base64.StdEncoding.DecodeString(entry[1]); err == nil {
return decoded
}
}
}
return nil
}
// ImageExtension returns the file extension for the image, either "png" or "jpeg"
func (m Metadata) ImageExtension() string {
for _, entry := range m {
if len(entry) == 2 && strings.Split(entry[0], "/")[0] == "image" {
spl := strings.Split(entry[0], "/")
if len(spl) == 2 {
return strings.Split(spl[1], ";")[0]
}
}
}
return ""
}
// Entry returns an arbitrary entry from the metadata array.
// eg.: "video/mp4" or "application/vnd.some-specific-thing-from-a-specific-app".
func (m Metadata) Entry(key string) string {
for _, entry := range m {
if len(entry) == 2 && entry[0] == key {
return entry[1]
}
}
return ""
}

73
vendor/github.com/fiatjaf/go-lnurl/withdraw.go generated vendored Normal file
View File

@@ -0,0 +1,73 @@
package lnurl
import (
"errors"
"net/url"
"strconv"
"github.com/tidwall/gjson"
)
type LNURLWithdrawResponse struct {
LNURLResponse
Tag string `json:"tag"`
K1 string `json:"k1"`
Callback string `json:"callback"`
CallbackURL *url.URL `json:"-"`
MaxWithdrawable int64 `json:"maxWithdrawable"`
MinWithdrawable int64 `json:"minWithdrawable"`
DefaultDescription string `json:"defaultDescription"`
BalanceCheck string `json:"balanceCheck,omitempty"`
}
func (_ LNURLWithdrawResponse) LNURLKind() string { return "lnurl-withdraw" }
func HandleWithdraw(j gjson.Result) (LNURLParams, error) {
callback := j.Get("callback").String()
callbackURL, err := url.Parse(callback)
if err != nil {
return nil, errors.New("callback is not a valid URL")
}
return LNURLWithdrawResponse{
Tag: "withdrawRequest",
K1: j.Get("k1").String(),
Callback: callback,
CallbackURL: callbackURL,
MaxWithdrawable: j.Get("maxWithdrawable").Int(),
MinWithdrawable: j.Get("minWithdrawable").Int(),
DefaultDescription: j.Get("defaultDescription").String(),
BalanceCheck: j.Get("balanceCheck").String(),
}, nil
}
func HandleFastWithdraw(query url.Values) (LNURLParams, bool) {
callback := query.Get("callback")
if callback == "" {
return nil, false
}
callbackURL, err := url.Parse(callback)
if err != nil {
return nil, false
}
maxWithdrawable, err := strconv.ParseInt(query.Get("maxWithdrawable"), 10, 64)
if err != nil {
return nil, false
}
minWithdrawable, err := strconv.ParseInt(query.Get("minWithdrawable"), 10, 64)
if err != nil {
return nil, false
}
balanceCheck := query.Get("balanceCheck")
return LNURLWithdrawResponse{
Tag: "withdrawRequest",
K1: query.Get("k1"),
Callback: callback,
CallbackURL: callbackURL,
MaxWithdrawable: maxWithdrawable,
MinWithdrawable: minWithdrawable,
DefaultDescription: query.Get("defaultDescription"),
BalanceCheck: balanceCheck,
}, true
}