diff --git a/cmd/tsconnect/wasm/wasm_js.go b/cmd/tsconnect/wasm/wasm_js.go index cefd3551b..468470d8a 100644 --- a/cmd/tsconnect/wasm/wasm_js.go +++ b/cmd/tsconnect/wasm/wasm_js.go @@ -31,11 +31,12 @@ import ( "tailscale.com/ipn/ipnlocal" "tailscale.com/ipn/ipnserver" "tailscale.com/ipn/store/mem" + "tailscale.com/logpolicy" + "tailscale.com/logtail" "tailscale.com/net/netns" "tailscale.com/net/tsdial" "tailscale.com/safesocket" "tailscale.com/tailcfg" - "tailscale.com/types/logger" "tailscale.com/wgengine" "tailscale.com/wgengine/netstack" "tailscale.com/words" @@ -56,7 +57,25 @@ func main() { func newIPN(jsConfig js.Value) map[string]any { netns.SetEnabled(false) - var logf logger.Logf = log.Printf + + jsStateStorage := jsConfig.Get("stateStorage") + var store ipn.StateStore + if jsStateStorage.IsUndefined() { + store = new(mem.Store) + } else { + store = &jsStateStore{jsStateStorage} + } + + lpc := getOrCreateLogPolicyConfig(store) + c := logtail.Config{ + Collection: lpc.Collection, + PrivateID: lpc.PrivateID, + // NewZstdEncoder is intentionally not passed in, compressed requests + // set HTTP headers that are not supported by the no-cors fetching mode. + HTTPC: &http.Client{Transport: &noCORSTransport{http.DefaultTransport}}, + } + logtail := logtail.NewLogger(c, log.Printf) + logf := logtail.Logf dialer := new(tsdial.Dialer) eng, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{ @@ -86,14 +105,7 @@ func newIPN(jsConfig js.Value) map[string]any { return ns.DialContextTCP(ctx, dst) } - jsStateStorage := jsConfig.Get("stateStorage") - var store ipn.StateStore - if jsStateStorage.IsUndefined() { - store = new(mem.Store) - } else { - store = &jsStateStore{jsStateStorage} - } - srv, err := ipnserver.New(log.Printf, "some-logid", store, eng, dialer, nil, ipnserver.Options{ + srv, err := ipnserver.New(logf, lpc.PublicID.String(), store, eng, dialer, nil, ipnserver.Options{ SurviveDisconnects: true, LoginFlags: controlclient.LoginEphemeral, }) @@ -527,3 +539,40 @@ func makePromise(f func() (any, error)) js.Value { promiseConstructor := js.Global().Get("Promise") return promiseConstructor.New(handler) } + +const logPolicyStateKey = "log-policy" + +func getOrCreateLogPolicyConfig(state ipn.StateStore) *logpolicy.Config { + if configBytes, err := state.ReadState(logPolicyStateKey); err == nil { + if config, err := logpolicy.ConfigFromBytes(configBytes); err == nil { + return config + } else { + log.Printf("Could not parse log policy config: %v", err) + } + } else if err != ipn.ErrStateNotExist { + log.Printf("Could not get log policy config from state store: %v", err) + } + config := logpolicy.NewConfig(logtail.CollectionNode) + if err := state.WriteState(logPolicyStateKey, config.ToBytes()); err != nil { + log.Printf("Could not save log policy config to state store: %v", err) + } + return config +} + +// noCORSTransport wraps a RoundTripper and forces the no-cors mode on requests, +// so that we can use it with non-CORS-aware servers. +type noCORSTransport struct { + http.RoundTripper +} + +func (t *noCORSTransport) RoundTrip(req *http.Request) (*http.Response, error) { + req.Header.Set("js.fetch:mode", "no-cors") + resp, err := t.RoundTripper.RoundTrip(req) + if err == nil { + // In no-cors mode no response properties are returned. Populate just + // the status so that callers do not think this was an error. + resp.StatusCode = http.StatusOK + resp.Status = http.StatusText(http.StatusOK) + } + return resp, err +} diff --git a/logtail/filch/filch_js.go b/logtail/filch/filch_js.go new file mode 100644 index 000000000..69358925e --- /dev/null +++ b/logtail/filch/filch_js.go @@ -0,0 +1,22 @@ +// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package filch + +import ( + "os" +) + +func saveStderr() (*os.File, error) { + return os.Stderr, nil +} + +func unsaveStderr(f *os.File) error { + os.Stderr = f + return nil +} + +func dup2Stderr(f *os.File) error { + return nil +} diff --git a/logtail/filch/filch_unix.go b/logtail/filch/filch_unix.go index 4bd6b2cd4..be18e1432 100644 --- a/logtail/filch/filch_unix.go +++ b/logtail/filch/filch_unix.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !windows -// +build !windows +//go:build !windows && !js +// +build !windows,!js package filch