mirror of
https://github.com/muun/recovery.git
synced 2025-11-13 07:11:45 -05:00
Release v2.2.0
This commit is contained in:
21
vendor/github.com/fiatjaf/go-lnurl/LICENSE
generated
vendored
Normal file
21
vendor/github.com/fiatjaf/go-lnurl/LICENSE
generated
vendored
Normal 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
6
vendor/github.com/fiatjaf/go-lnurl/README.md
generated
vendored
Normal 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
48
vendor/github.com/fiatjaf/go-lnurl/aes.go
generated
vendored
Normal 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
55
vendor/github.com/fiatjaf/go-lnurl/auth.go
generated
vendored
Normal 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
37
vendor/github.com/fiatjaf/go-lnurl/base.go
generated
vendored
Normal 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
241
vendor/github.com/fiatjaf/go-lnurl/bech32.go
generated
vendored
Normal 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
39
vendor/github.com/fiatjaf/go-lnurl/channel.go
generated
vendored
Normal 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
39
vendor/github.com/fiatjaf/go-lnurl/codec.go
generated
vendored
Normal 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
8
vendor/github.com/fiatjaf/go-lnurl/go.mod
generated
vendored
Normal 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
35
vendor/github.com/fiatjaf/go-lnurl/go.sum
generated
vendored
Normal 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
83
vendor/github.com/fiatjaf/go-lnurl/handle.go
generated
vendored
Normal 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
29
vendor/github.com/fiatjaf/go-lnurl/helpers.go
generated
vendored
Normal 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
202
vendor/github.com/fiatjaf/go-lnurl/pay.go
generated
vendored
Normal 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
73
vendor/github.com/fiatjaf/go-lnurl/withdraw.go
generated
vendored
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user