mirror of
https://github.com/nbd-wtf/satdress.git
synced 2024-11-11 16:30:35 +00:00
chore: merge conflicts
This commit is contained in:
commit
e8ca881ba7
2
Makefile
2
Makefile
|
@ -1,4 +1,4 @@
|
|||
satdress: $(shell find . -name "*.go")
|
||||
satdress: $(shell find . -name "*.go") index.html go.mod
|
||||
CC=$$(which musl-gcc) go build -ldflags='-s -w -linkmode external -extldflags "-static"' -o ./satdress
|
||||
|
||||
deploy: satdress
|
||||
|
|
63
db.go
63
db.go
|
@ -1,5 +1,17 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/cockroachdb/pebble"
|
||||
)
|
||||
|
||||
type Params struct {
|
||||
Name string
|
||||
Kind string
|
||||
|
@ -8,3 +20,54 @@ type Params struct {
|
|||
Pak string
|
||||
Waki string
|
||||
}
|
||||
|
||||
func SaveName(
|
||||
name string,
|
||||
params *Params,
|
||||
providedPin string,
|
||||
) (pin string, inv string, err error) {
|
||||
name = strings.ToLower(name)
|
||||
key := []byte(name)
|
||||
|
||||
mac := hmac.New(sha256.New, []byte(s.Secret))
|
||||
mac.Write([]byte(name + "@" + s.Domain))
|
||||
pin = hex.EncodeToString(mac.Sum(nil))
|
||||
|
||||
if _, closer, err := db.Get(key); err == nil {
|
||||
defer closer.Close()
|
||||
if pin != providedPin {
|
||||
return "", "", errors.New("name already exists! must provide pin.")
|
||||
}
|
||||
}
|
||||
|
||||
// check if the given data works
|
||||
if inv, err = makeInvoice(params, 1000); err != nil {
|
||||
return "", "", fmt.Errorf("couldn't make an invoice with the given data: %w", err)
|
||||
}
|
||||
|
||||
// save it
|
||||
data, _ := json.Marshal(params)
|
||||
if err := db.Set(key, data, pebble.Sync); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return pin, inv, nil
|
||||
}
|
||||
|
||||
func GetName(name string) (*Params, error) {
|
||||
name = strings.ToLower(name)
|
||||
|
||||
val, closer, err := db.Get([]byte(name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer closer.Close()
|
||||
|
||||
var params Params
|
||||
if err := json.Unmarshal(val, ¶ms); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
params.Name = name
|
||||
return ¶ms, nil
|
||||
}
|
||||
|
|
3
go.mod
3
go.mod
|
@ -5,8 +5,9 @@ go 1.16
|
|||
require (
|
||||
github.com/cockroachdb/pebble v0.0.0-20210812144839-61318a019370
|
||||
github.com/fiatjaf/go-lnurl v1.4.0
|
||||
github.com/fiatjaf/makeinvoice v1.2.0
|
||||
github.com/fiatjaf/makeinvoice v1.2.3
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/joho/godotenv v1.3.0 // indirect
|
||||
github.com/kelseyhightower/envconfig v1.4.0
|
||||
github.com/lib/pq v1.10.2
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||
|
|
6
go.sum
6
go.sum
|
@ -119,8 +119,8 @@ github.com/fiatjaf/lightningd-gjson-rpc v1.4.0 h1:Iv5tt4YuNoSMfR39wiV0tqnHYTJ85o
|
|||
github.com/fiatjaf/lightningd-gjson-rpc v1.4.0/go.mod h1:SQGA0qcY2qypaMXDQlE5V5+2MnLZzQ7NzfRsScliFeE=
|
||||
github.com/fiatjaf/ln-decodepay v1.0.0 h1:1YUMjvLock+BicMNwoZ/OA3oG2ZYEaJ8AzdS6EGVMTQ=
|
||||
github.com/fiatjaf/ln-decodepay v1.0.0/go.mod h1:/LWK+ZUa3i8MqbRjIMAiVQS2+NbhwKWlwib2n446cMQ=
|
||||
github.com/fiatjaf/makeinvoice v1.2.0 h1:lWvjFyMq3R9yzln/I67Ex2/c0cBUiuWS4WEc32AWuNc=
|
||||
github.com/fiatjaf/makeinvoice v1.2.0/go.mod h1:R+p/0XfRNob2hu+nyIiC2xaSy/HcdQ21rbNNuUHRB70=
|
||||
github.com/fiatjaf/makeinvoice v1.2.3 h1:a2tvuv4q823+2Q7gw9QGoPGhhTQ2LmMzgQjDF9zKXeM=
|
||||
github.com/fiatjaf/makeinvoice v1.2.3/go.mod h1:R+p/0XfRNob2hu+nyIiC2xaSy/HcdQ21rbNNuUHRB70=
|
||||
github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA=
|
||||
github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
|
@ -203,6 +203,8 @@ github.com/jackpal/go-nat-pmp v0.0.0-20170405195558-28a68d0c24ad/go.mod h1:QPH04
|
|||
github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag=
|
||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI=
|
||||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
|
|
32
grab.html
Normal file
32
grab.html
Normal file
|
@ -0,0 +1,32 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Satdress - Name Saved</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" type="image/png" href="https://i.imgur.com/4yaPtA2.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="/static/style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main id="main">
|
||||
name saved! this is your secret pin key for this name: {{ pin }}
|
||||
this is the test invoice we've generated: {{ invoice }}
|
||||
</main>
|
||||
<script
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.2.2/vue.global.prod.min.js"
|
||||
></script>
|
||||
<script>
|
||||
const initial = {} // REPLACED WITH SERVER DATA
|
||||
|
||||
const Main = {
|
||||
data() {
|
||||
return {
|
||||
...initial,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Vue.createApp(Main).mount('#main');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
37
html.go
Normal file
37
html.go
Normal file
|
@ -0,0 +1,37 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type BaseData struct {
|
||||
Domain string `json:"domain"`
|
||||
SiteOwnerName string `json:"siteOwnerName"`
|
||||
SiteOwnerURL string `json:"siteOwnerURL"`
|
||||
SiteName string `json:"siteName"`
|
||||
}
|
||||
|
||||
func renderHTML(w http.ResponseWriter, html string, extraData interface{}) {
|
||||
base, _ := json.Marshal(BaseData{
|
||||
Domain: s.Domain,
|
||||
SiteOwnerName: s.SiteOwnerName,
|
||||
SiteOwnerURL: s.SiteOwnerURL,
|
||||
SiteName: s.SiteName,
|
||||
})
|
||||
extra, _ := json.Marshal(extraData)
|
||||
|
||||
w.Header().Set("content-type", "text/html")
|
||||
fmt.Fprint(w,
|
||||
strings.ReplaceAll(
|
||||
strings.ReplaceAll(
|
||||
html,
|
||||
"{} // REPLACED WITH SERVER DATA",
|
||||
fmt.Sprintf("{...%s, ...%s}", string(base), string(extra)),
|
||||
),
|
||||
"Satdress", s.SiteName,
|
||||
),
|
||||
)
|
||||
}
|
281
index.html
281
index.html
|
@ -5,6 +5,7 @@
|
|||
<meta charset="utf-8" />
|
||||
<link rel="icon" type="image/png" href="https://i.imgur.com/4yaPtA2.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="/static/style.css" />
|
||||
<meta
|
||||
property="og:title"
|
||||
content="Satdress - Federated Lightning Address Server"
|
||||
|
@ -33,191 +34,6 @@
|
|||
<meta name="twitter:description" content="Satdress is a Federated Lightning Address server allowing you to connect Lightning nodes to Lightning Addresses. Satdress follows the Lightning Address protocol and aims to provide an easy-to-deploy Bridge Server." />
|
||||
<meta name="twitter:image" content="https://i.imgur.com/PsT2uoR.png" />
|
||||
</head>
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #f3f3f3;
|
||||
flex-direction: column;
|
||||
font-family: 'PT Sans';
|
||||
justify-content: center;
|
||||
padding: 60px 20px 40px 20px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 40px;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.tagline {
|
||||
opacity: 0.7;
|
||||
font-size: 18px;
|
||||
font-weight: 400;
|
||||
text-align: center;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.description {
|
||||
opacity: 0.7;
|
||||
font-size: 18px;
|
||||
font-weight: 400;
|
||||
max-width: 320px;
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.card {
|
||||
max-width: 400px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 30px 40px;
|
||||
margin: 20px 0 20px;
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
.submit-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.submit {
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
outline: none;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
margin-top: 20px;
|
||||
padding: 12px 8px;
|
||||
border-radius: 8px;
|
||||
letter-spacing: 0.5px;
|
||||
border: 1px solid rgba(86, 46, 249, 0.85);
|
||||
background-color: rgba(86, 46, 249, 0.75);
|
||||
}
|
||||
|
||||
.submit:hover {
|
||||
background-color: rgba(86, 46, 249, 0.85);
|
||||
}
|
||||
|
||||
.label {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 5px;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.input {
|
||||
height: 35px;
|
||||
outline: none;
|
||||
padding: 0 10px;
|
||||
font-size: 14px;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 25px;
|
||||
letter-spacing: 0.5px;
|
||||
border: 1px solid #999;
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
|
||||
.suffix {
|
||||
height: 35px;
|
||||
display: inline-flex;
|
||||
padding: 0 10px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
align-items: center;
|
||||
word-break: break-all;
|
||||
margin-bottom: 25px;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
select {
|
||||
height: 35px;
|
||||
outline: none;
|
||||
padding: 0 5px;
|
||||
font-size: 14px;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 25px;
|
||||
letter-spacing: 0.5px;
|
||||
border: 1px solid #999;
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
|
||||
label {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.resources {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.resource-button {
|
||||
padding: 8px;
|
||||
color: #8062fb;
|
||||
font-weight: 400;
|
||||
margin-bottom: 8px;
|
||||
border-radius: 7px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.resource-button:hover {
|
||||
color: #8062fb;
|
||||
background: rgba(42,0,255,0.1);
|
||||
}
|
||||
|
||||
.owner {
|
||||
display: flex;
|
||||
padding-top: 5px;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.owner-button {
|
||||
padding: 8px;
|
||||
color: #8062fb;
|
||||
font-weight: 400;
|
||||
margin-bottom: 8px;
|
||||
border-radius: 7px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.owner-button:hover {
|
||||
color: #8062fb;
|
||||
background: rgba(42,0,255,0.1);
|
||||
}
|
||||
|
||||
.owner-name {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
body {
|
||||
padding: 20px 5px 30px 5px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
.tagline {
|
||||
font-size: 16px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<main id="main">
|
||||
<div class="title">{{ siteName }}Satdress</div>
|
||||
|
@ -233,67 +49,79 @@
|
|||
<div class="card">
|
||||
<div class="description">Use the form below to connect your own node to a <b>Lightning Address</b>.</div>
|
||||
<form action="/grab" method="post">
|
||||
<label>
|
||||
<p class="label">
|
||||
Desired Username
|
||||
</p>
|
||||
<div class="field">
|
||||
<div class="row" style="justify-content: space-between">
|
||||
<label for="name">
|
||||
Desired Username
|
||||
</label>
|
||||
<label style="float: right">
|
||||
Is New?
|
||||
<input type="checkbox" v-model="isNew">
|
||||
</label>
|
||||
</div>
|
||||
<div style="position: relative;">
|
||||
<input class="input" name="name">
|
||||
<input class="input" name="name" id="name">
|
||||
<span class="suffix" style="position: absolute;">@{{ domain }}</span>
|
||||
</div>
|
||||
</label>
|
||||
<label>
|
||||
<p class="label">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="kind">
|
||||
Node Backend Type
|
||||
</p>
|
||||
<select name="kind" v-model="kind">
|
||||
</label>
|
||||
<select name="kind" id="kind" id="kind" v-model="kind">
|
||||
<option value="lnd">LND</option>
|
||||
<option value="sparko">Sparko</option>
|
||||
<option value="lnpay">LNPay</option>
|
||||
<option value="lnbits">LNbits</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div v-if="kind == 'lnd'">
|
||||
<label>
|
||||
<p class="label">
|
||||
<div class="field">
|
||||
<label for="host">
|
||||
Host (IP or Domain + Port)
|
||||
</p>
|
||||
<input class="input" name="host">
|
||||
</label>
|
||||
<label>
|
||||
<p class="label">
|
||||
</label>
|
||||
<input class="input" name="host" id="host">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="key">
|
||||
Invoice Macaroon
|
||||
</p>
|
||||
<input class="input" name="key">
|
||||
</label>
|
||||
</label>
|
||||
<input class="input" name="key" id="key">
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="kind == 'sparko' || kind == 'lnbits'">
|
||||
<label>
|
||||
<p class="label">
|
||||
<div class="field">
|
||||
<label for="host">
|
||||
Host (IP or Domain + Port)
|
||||
</p>
|
||||
<input class="input" name="host">
|
||||
</label>
|
||||
<label>
|
||||
<p class="label">
|
||||
</label>
|
||||
<input class="input" name="host" id="host">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="key">
|
||||
Key
|
||||
</p>
|
||||
<input class="input" name="key">
|
||||
</label>
|
||||
</label>
|
||||
<input class="input" name="key" id="key">
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="kind == 'lnpay'">
|
||||
<label>
|
||||
<p class="label">
|
||||
<div class="field">
|
||||
<label for="pak">
|
||||
Public Access Key (pak)
|
||||
</p>
|
||||
<input class="input" name="pak">
|
||||
</label>
|
||||
<label>
|
||||
<p class="label">
|
||||
</label>
|
||||
<input class="input" name="pak" id="pak">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="waki">
|
||||
Wallet Invoice Key (waki)
|
||||
</p>
|
||||
<input class="input" name="waki">
|
||||
</label>
|
||||
<input class="input" name="waki" id="waki">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field" v-if="!isNew">
|
||||
<label for="pin">
|
||||
Pin
|
||||
</label>
|
||||
<input class="input" name="pin" id="pin">
|
||||
</div>
|
||||
<button class="submit">Submit</button>
|
||||
</form>
|
||||
|
@ -317,12 +145,13 @@
|
|||
src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.2.2/vue.global.prod.min.js"
|
||||
></script>
|
||||
<script>
|
||||
const initial = {} // REPLACED WITH SERVER DATA // {siteOwnerName, siteOwnerURL, siteName, domain}
|
||||
const initial = {} // REPLACED WITH SERVER DATA //
|
||||
|
||||
const Main = {
|
||||
data() {
|
||||
return {
|
||||
kind: 'lnd',
|
||||
isNew: true,
|
||||
...initial,
|
||||
}
|
||||
}
|
||||
|
|
21
lnurl.go
21
lnurl.go
|
@ -6,7 +6,6 @@ import (
|
|||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/cockroachdb/pebble"
|
||||
"github.com/fiatjaf/go-lnurl"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
@ -14,24 +13,16 @@ import (
|
|||
func handleLNURL(w http.ResponseWriter, r *http.Request) {
|
||||
username := mux.Vars(r)["username"]
|
||||
|
||||
log.Info().Str("username", username).Msg("got lnurl request")
|
||||
|
||||
var params Params
|
||||
val, closer, err := db.Get([]byte(username))
|
||||
params, err := GetName(username)
|
||||
if err != nil {
|
||||
if err != pebble.ErrNotFound {
|
||||
log.Error().Err(err).Str("name", username).
|
||||
Msg("error getting data")
|
||||
}
|
||||
return
|
||||
}
|
||||
defer closer.Close()
|
||||
if err := json.Unmarshal(val, ¶ms); err != nil {
|
||||
log.Error().Err(err).Str("name", username).Str("data", string(val)).
|
||||
Msg("got broken json from db")
|
||||
log.Error().Err(err).Str("name", username).Msg("failed to get name")
|
||||
json.NewEncoder(w).Encode(lnurl.ErrorResponse(fmt.Sprintf(
|
||||
"failed to get name %s", username)))
|
||||
return
|
||||
}
|
||||
|
||||
log.Info().Str("username", username).Msg("got lnurl request")
|
||||
|
||||
if amount := r.URL.Query().Get("amount"); amount == "" {
|
||||
// check if the receiver accepts comments
|
||||
var commentLength int64 = 0
|
||||
|
|
78
main.go
78
main.go
|
@ -1,11 +1,8 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"embed"
|
||||
_ "embed"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
@ -35,7 +32,13 @@ var router = mux.NewRouter()
|
|||
var log = zerolog.New(os.Stderr).Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
||||
|
||||
//go:embed index.html
|
||||
var html string
|
||||
var indexHTML string
|
||||
|
||||
//go:embed grab.html
|
||||
var grabHTML string
|
||||
|
||||
//go:embed static
|
||||
var static embed.FS
|
||||
|
||||
func main() {
|
||||
err := envconfig.Process("", &s)
|
||||
|
@ -43,6 +46,8 @@ func main() {
|
|||
log.Fatal().Err(err).Msg("couldn't process envconfig.")
|
||||
}
|
||||
|
||||
s.Domain = strings.ToLower(s.Domain)
|
||||
|
||||
db, err = pebble.Open(s.Domain, nil)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Str("path", s.Domain).Msg("failed to open db.")
|
||||
|
@ -53,72 +58,31 @@ func main() {
|
|||
|
||||
router.Path("/").HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("content-type", "text/html")
|
||||
serverData, _ := json.Marshal(struct {
|
||||
Domain string `json:"domain"`
|
||||
SiteOwnerName string `json:"siteOwnerName"`
|
||||
SiteOwnerURL string `json:"siteOwnerURL"`
|
||||
SiteName string `json:"siteName"`
|
||||
}{
|
||||
Domain: s.Domain,
|
||||
SiteOwnerName: s.SiteOwnerName,
|
||||
SiteOwnerURL: s.SiteOwnerURL,
|
||||
SiteName: s.SiteName,
|
||||
})
|
||||
fmt.Fprintf(w,
|
||||
strings.ReplaceAll(
|
||||
strings.ReplaceAll(
|
||||
html, "{} // REPLACED WITH SERVER DATA", string(serverData),
|
||||
),
|
||||
"Satdress", s.SiteName,
|
||||
),
|
||||
)
|
||||
renderHTML(w, indexHTML, map[string]interface{}{})
|
||||
},
|
||||
)
|
||||
|
||||
router.PathPrefix("/static/").Handler(http.FileServer(http.FS(static)))
|
||||
|
||||
router.Path("/grab").HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
name := []byte(r.FormValue("name"))
|
||||
|
||||
mac := hmac.New(sha256.New, []byte(s.Secret))
|
||||
mac.Write(name)
|
||||
pin := hex.EncodeToString(mac.Sum(nil))
|
||||
|
||||
if _, closer, err := db.Get(name); err == nil {
|
||||
w.WriteHeader(401)
|
||||
fmt.Fprint(w,
|
||||
"name already exists! must provide pin (contact support).")
|
||||
return
|
||||
} else if err == nil {
|
||||
closer.Close()
|
||||
}
|
||||
|
||||
params := Params{
|
||||
pin, inv, err := SaveName(r.FormValue("name"), &Params{
|
||||
Kind: r.FormValue("kind"),
|
||||
Host: r.FormValue("host"),
|
||||
Key: r.FormValue("key"),
|
||||
Pak: r.FormValue("pak"),
|
||||
Waki: r.FormValue("waki"),
|
||||
}
|
||||
|
||||
// check if the given data works
|
||||
if _, err := makeInvoice(params, 1000); err != nil {
|
||||
w.WriteHeader(400)
|
||||
fmt.Fprint(w, "couldn't make an invoice with the given data: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// save it
|
||||
data, _ := json.Marshal(params)
|
||||
if err := db.Set(name, data, pebble.Sync); err != nil {
|
||||
}, r.FormValue("pin"))
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
fmt.Fprint(w, "error! "+err.Error())
|
||||
fmt.Fprint(w, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintf(w,
|
||||
"name saved! this is your secret pin key for this name: %s",
|
||||
pin)
|
||||
renderHTML(w, grabHTML, struct {
|
||||
PIN string `json:"pin"`
|
||||
Invoice string `json:"invoice"`
|
||||
}{pin, inv})
|
||||
},
|
||||
)
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
|
@ -9,7 +10,7 @@ import (
|
|||
"github.com/tidwall/sjson"
|
||||
)
|
||||
|
||||
func makeMetadata(params Params) string {
|
||||
func makeMetadata(params *Params) string {
|
||||
metadata, _ := sjson.Set("[]", "0.0", "text/identifier")
|
||||
metadata, _ = sjson.Set(metadata, "0.1", params.Name+"@"+s.Domain)
|
||||
|
||||
|
@ -21,7 +22,7 @@ func makeMetadata(params Params) string {
|
|||
return metadata
|
||||
}
|
||||
|
||||
func makeInvoice(params Params, msat int) (bolt11 string, err error) {
|
||||
func makeInvoice(params *Params, msat int) (bolt11 string, err error) {
|
||||
// description_hash
|
||||
h := sha256.Sum256([]byte(makeMetadata(params)))
|
||||
|
||||
|
@ -50,6 +51,11 @@ func makeInvoice(params Params, msat int) (bolt11 string, err error) {
|
|||
}
|
||||
}
|
||||
|
||||
log.Debug().Int("msatoshi", msat).
|
||||
Interface("backend", backend).
|
||||
Str("description_hash", hex.EncodeToString(h[:])).
|
||||
Msg("generating invoice")
|
||||
|
||||
// actually generate the invoice
|
||||
return makeinvoice.MakeInvoice(makeinvoice.Params{
|
||||
Msatoshi: int64(msat),
|
||||
|
|
188
static/style.css
Normal file
188
static/style.css
Normal file
|
@ -0,0 +1,188 @@
|
|||
body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #f3f3f3;
|
||||
flex-direction: column;
|
||||
font-family: 'PT Sans';
|
||||
justify-content: center;
|
||||
padding: 60px 20px 40px 20px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 40px;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.tagline {
|
||||
opacity: 0.7;
|
||||
font-size: 18px;
|
||||
font-weight: 400;
|
||||
text-align: center;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.description {
|
||||
opacity: 0.7;
|
||||
font-size: 18px;
|
||||
font-weight: 400;
|
||||
max-width: 320px;
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.card {
|
||||
max-width: 400px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 30px 40px;
|
||||
margin: 20px 0 20px;
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
.submit-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.submit {
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
outline: none;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
margin-top: 20px;
|
||||
padding: 12px 8px;
|
||||
border-radius: 8px;
|
||||
letter-spacing: 0.5px;
|
||||
border: 1px solid rgba(86, 46, 249, 0.85);
|
||||
background-color: rgba(86, 46, 249, 0.75);
|
||||
}
|
||||
|
||||
.submit:hover {
|
||||
background-color: rgba(86, 46, 249, 0.85);
|
||||
}
|
||||
|
||||
.field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
label {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 5px;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.input {
|
||||
height: 35px;
|
||||
outline: none;
|
||||
padding: 0 10px;
|
||||
font-size: 14px;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 25px;
|
||||
letter-spacing: 0.5px;
|
||||
border: 1px solid #999;
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
|
||||
.suffix {
|
||||
height: 35px;
|
||||
display: inline-flex;
|
||||
padding: 0 10px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
align-items: center;
|
||||
word-break: break-all;
|
||||
margin-bottom: 25px;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
select {
|
||||
height: 35px;
|
||||
outline: none;
|
||||
padding: 0 5px;
|
||||
font-size: 14px;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 25px;
|
||||
letter-spacing: 0.5px;
|
||||
border: 1px solid #999;
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
|
||||
.resources {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.resource-button {
|
||||
padding: 8px;
|
||||
color: #8062fb;
|
||||
font-weight: 400;
|
||||
margin-bottom: 8px;
|
||||
border-radius: 7px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.resource-button:hover {
|
||||
color: #8062fb;
|
||||
background: rgba(42,0,255,0.1);
|
||||
}
|
||||
|
||||
.owner {
|
||||
display: flex;
|
||||
padding-top: 5px;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.owner-button {
|
||||
padding: 8px;
|
||||
color: #8062fb;
|
||||
font-weight: 400;
|
||||
margin-bottom: 8px;
|
||||
border-radius: 7px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.owner-button:hover {
|
||||
color: #8062fb;
|
||||
background: rgba(42,0,255,0.1);
|
||||
}
|
||||
|
||||
.owner-name {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
body {
|
||||
padding: 20px 5px 30px 5px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
.tagline {
|
||||
font-size: 16px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user