Skip to content

Commit 74875eb

Browse files
committed
wasm-client+example: extract session expiry
1 parent f2b3d71 commit 74875eb

File tree

4 files changed

+93
-3
lines changed

4 files changed

+93
-3
lines changed

cmd/wasm-client/go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ require (
1010
github.com/lightninglabs/pool v0.5.6-alpha
1111
github.com/lightningnetwork/lnd v0.15.0-beta.rc3
1212
google.golang.org/grpc v1.39.0
13+
gopkg.in/macaroon-bakery.v2 v2.0.1
14+
gopkg.in/macaroon.v2 v2.1.0
1315
)
1416

1517
replace github.com/lightninglabs/lightning-node-connect => ../../

cmd/wasm-client/main.go

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"net/http"
1313
"os"
1414
"runtime/debug"
15+
"strings"
1516
"syscall/js"
1617

1718
"github.com/btcsuite/btcd/btcec/v2"
@@ -34,6 +35,8 @@ import (
3435
"github.com/lightningnetwork/lnd/lnrpc/wtclientrpc"
3536
"github.com/lightningnetwork/lnd/signal"
3637
"google.golang.org/grpc"
38+
"gopkg.in/macaroon-bakery.v2/bakery/checkers"
39+
"gopkg.in/macaroon.v2"
3740
)
3841

3942
type stubPackageRegistration func(map[string]func(context.Context,
@@ -104,6 +107,7 @@ func main() {
104107
callbacks.Set("wasmClientDisconnect", js.FuncOf(wc.Disconnect))
105108
callbacks.Set("wasmClientInvokeRPC", js.FuncOf(wc.InvokeRPC))
106109
callbacks.Set("wasmClientStatus", js.FuncOf(wc.Status))
110+
callbacks.Set("wasmClientGetExpiry", js.FuncOf(wc.GetExpiry))
107111
js.Global().Set(cfg.NameSpace, callbacks)
108112

109113
for _, registration := range registrations {
@@ -127,6 +131,8 @@ type wasmClient struct {
127131

128132
statusChecker func() mailbox.ConnStatus
129133

134+
mac *macaroon.Macaroon
135+
130136
registry map[string]func(context.Context, *grpc.ClientConn,
131137
string, func(string, error))
132138
}
@@ -202,10 +208,28 @@ func (w *wasmClient) ConnectServer(_ js.Value, args []js.Value) interface{} {
202208
),
203209
)
204210
}, func(data []byte) error {
211+
parts := strings.Split(string(data), ": ")
212+
if len(parts) != 2 || parts[0] != "Macaroon" {
213+
return fmt.Errorf("authdata does " +
214+
"not contain a macaroon")
215+
}
216+
217+
macBytes, err := hex.DecodeString(parts[1])
218+
if err != nil {
219+
return err
220+
}
221+
222+
mac := &macaroon.Macaroon{}
223+
err = mac.UnmarshalBinary(macBytes)
224+
if err != nil {
225+
return fmt.Errorf("unable to decode "+
226+
"macaroon: %v", err)
227+
}
228+
229+
w.mac = mac
230+
205231
return callJsCallback(
206-
w.cfg.OnAuthData, hex.EncodeToString(
207-
data,
208-
),
232+
w.cfg.OnAuthData, string(data),
209233
)
210234
},
211235
)
@@ -281,6 +305,49 @@ func (w *wasmClient) InvokeRPC(_ js.Value, args []js.Value) interface{} {
281305

282306
}
283307

308+
func (w *wasmClient) GetExpiry(_ js.Value, _ []js.Value) interface{} {
309+
if w.mac == nil {
310+
log.Errorf("macaroon not obtained yet. GetExpiry should " +
311+
"only be called once the connection is complete")
312+
return nil
313+
}
314+
315+
expiry, found := checkers.ExpiryTime(nil, w.mac.Caveats())
316+
if !found {
317+
return nil
318+
}
319+
320+
return js.ValueOf(expiry.Unix())
321+
}
322+
if len(args) != 1 {
323+
return js.ValueOf("invalid use of wasmClientExtractExpiry, " +
324+
"need 1 parameters: macaroon string")
325+
}
326+
327+
parts := strings.Split(args[0].String(), ": ")
328+
if len(parts) != 2 || parts[0] != "Macaroon" {
329+
return js.ValueOf("macaroon missing from auth data")
330+
}
331+
332+
macBytes, err := hex.DecodeString(parts[1])
333+
if err != nil {
334+
return js.ValueOf(err.Error())
335+
}
336+
337+
mac := &macaroon.Macaroon{}
338+
if err := mac.UnmarshalBinary(macBytes); err != nil {
339+
return js.ValueOf(fmt.Sprintf("unable to decode macaroon: %v",
340+
err))
341+
}
342+
343+
expiry, found := checkers.ExpiryTime(nil, mac.Caveats())
344+
if !found {
345+
return nil
346+
}
347+
348+
return js.ValueOf(expiry.Unix())
349+
}
350+
284351
// validateArgs checks that the correct keys and callback functions have been
285352
// provided.
286353
func validateArgs(cfg *config, localPrivKey, remotePubKey string) error {

cmd/wasm-client/permissions.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package main

example/index.html

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@
3333
server = localStorage.getItem(namespace+":mailboxHost")
3434
document.getElementById('server').value = server
3535
}
36+
if (localStorage.getItem(namespace + ":expiry")) {
37+
let expiry = new Date(localStorage.getItem(namespace + ":expiry") * 1000);
38+
if (expiry < Date.now()) {
39+
document.getElementById('expiry').innerHTML = "Session has expired";
40+
return
41+
}
42+
}
3643

3744
console.clear();
3845
go.argv = [
@@ -156,6 +163,17 @@
156163

157164
function onAuthData(data) {
158165
console.log("auth data received: "+data)
166+
167+
// extract expiry.
168+
let expiry = window[namespace].wasmClientGetExpiry();
169+
if (!expiry) {
170+
document.getElementById('expiry').innerHTML = "No expiry found in macaroon";
171+
return {}
172+
}
173+
174+
localStorage.setItem(namespace+":expiry", expiry)
175+
document.getElementById('expiry').innerHTML = "Session Expiry: "+new Date(expiry*1000).toLocaleString();
176+
159177
return {}
160178
// In case of an error, return an object with the following structure:
161179
// `return {err:"this totally failed"}`
@@ -183,6 +201,8 @@ <h4>Now connect to the server with the session passphrase</h4>
183201

184202
<h4 id="status"></h4>
185203

204+
<h4 id="expiry"></h4>
205+
186206
<br />
187207

188208
<div id="ready" style="display:none">

0 commit comments

Comments
 (0)