diff --git a/cmd/tailscale/cli/up.go b/cmd/tailscale/cli/up.go index 1d9f7e17c..2a7465de1 100644 --- a/cmd/tailscale/cli/up.go +++ b/cmd/tailscale/cli/up.go @@ -94,8 +94,10 @@ func newUpFlagSet(goos string, upArgs *upArgsT, cmd string) *flag.FlagSet { // When adding new flags, prefer to put them under "tailscale set" instead // of here. Setting preferences via "tailscale up" is deprecated. - upf.BoolVar(&upArgs.qr, "qr", false, "show QR code for login URLs") - upf.StringVar(&upArgs.qrFormat, "qr-format", string(qrcodes.FormatAuto), fmt.Sprintf("QR code formatting (%s, %s, %s, %s)", qrcodes.FormatAuto, qrcodes.FormatASCII, qrcodes.FormatLarge, qrcodes.FormatSmall)) + if buildfeatures.HasQRCodes { + upf.BoolVar(&upArgs.qr, "qr", false, "show QR code for login URLs") + upf.StringVar(&upArgs.qrFormat, "qr-format", string(qrcodes.FormatAuto), fmt.Sprintf("QR code formatting (%s, %s, %s, %s)", qrcodes.FormatAuto, qrcodes.FormatASCII, qrcodes.FormatLarge, qrcodes.FormatSmall)) + } upf.StringVar(&upArgs.authKeyOrFile, "auth-key", "", `node authorization key; if it begins with "file:", then it's a path to a file containing the authkey`) upf.StringVar(&upArgs.clientID, "client-id", "", "Client ID used to generate authkeys via workload identity federation") upf.StringVar(&upArgs.clientSecretOrFile, "client-secret", "", `Client Secret used to generate authkeys via OAuth; if it begins with "file:", then it's a path to a file containing the secret`) @@ -720,9 +722,11 @@ func runUp(ctx context.Context, cmd string, args []string, upArgs upArgsT) (retE if upArgs.json { js := &upOutputJSON{AuthURL: authURL, BackendState: st.BackendState} - png, err := qrcodes.EncodePNG(authURL, 128) - if err == nil { - js.QR = "data:image/png;base64," + base64.StdEncoding.EncodeToString(png) + if buildfeatures.HasQRCodes { + png, err := qrcodes.EncodePNG(authURL, 128) + if err == nil { + js.QR = "data:image/png;base64," + base64.StdEncoding.EncodeToString(png) + } } data, err := json.MarshalIndent(js, "", "\t") @@ -733,7 +737,7 @@ func runUp(ctx context.Context, cmd string, args []string, upArgs upArgsT) (retE } } else { fmt.Fprintf(Stderr, "\nTo authenticate, visit:\n\n\t%s\n\n", authURL) - if upArgs.qr { + if upArgs.qr && buildfeatures.HasQRCodes { _, err := qrcodes.Fprintln(Stderr, qrcodes.Format(upArgs.qrFormat), authURL) if err != nil { log.Print(err) diff --git a/cmd/tailscale/deps_test.go b/cmd/tailscale/deps_test.go new file mode 100644 index 000000000..132940e3c --- /dev/null +++ b/cmd/tailscale/deps_test.go @@ -0,0 +1,22 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +package main + +import ( + "testing" + + "tailscale.com/tstest/deptest" +) + +func TestOmitQRCodes(t *testing.T) { + const msg = "unexpected with ts_omit_qrcodes" + deptest.DepChecker{ + GOOS: "linux", + GOARCH: "amd64", + Tags: "ts_omit_qrcodes", + BadDeps: map[string]string{ + "github.com/skip2/go-qrcode": msg, + }, + }.Check(t) +} diff --git a/cmd/tailscaled/depaware-minbox.txt b/cmd/tailscaled/depaware-minbox.txt index 38da38013..4b2f71983 100644 --- a/cmd/tailscaled/depaware-minbox.txt +++ b/cmd/tailscaled/depaware-minbox.txt @@ -33,9 +33,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de github.com/peterbourgon/ff/v3/ffcli from tailscale.com/cmd/tailscale/cli+ github.com/peterbourgon/ff/v3/internal from github.com/peterbourgon/ff/v3 💣 github.com/safchain/ethtool from tailscale.com/net/netkernelconf - github.com/skip2/go-qrcode from tailscale.com/util/qrcodes - github.com/skip2/go-qrcode/bitset from github.com/skip2/go-qrcode+ - github.com/skip2/go-qrcode/reedsolomon from github.com/skip2/go-qrcode 💣 github.com/tailscale/wireguard-go/conn from github.com/tailscale/wireguard-go/device+ 💣 github.com/tailscale/wireguard-go/device from tailscale.com/net/tstun+ github.com/tailscale/wireguard-go/ipc from github.com/tailscale/wireguard-go/device @@ -193,7 +190,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de tailscale.com/util/osshare from tailscale.com/cmd/tailscaled tailscale.com/util/osuser from tailscale.com/ipn/ipnlocal+ tailscale.com/util/prompt from tailscale.com/cmd/tailscale/cli - 💣 tailscale.com/util/qrcodes from tailscale.com/cmd/tailscale/cli + tailscale.com/util/qrcodes from tailscale.com/cmd/tailscale/cli tailscale.com/util/race from tailscale.com/net/dns/resolver tailscale.com/util/racebuild from tailscale.com/logpolicy tailscale.com/util/rands from tailscale.com/ipn/ipnlocal+ @@ -274,9 +271,8 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de bufio from compress/flate+ bytes from bufio+ cmp from encoding/json+ - compress/flate from compress/gzip+ + compress/flate from compress/gzip compress/gzip from net/http+ - compress/zlib from image/png container/list from crypto/tls+ context from crypto/tls+ crypto from crypto/ecdh+ @@ -355,13 +351,9 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de flag from tailscale.com/cmd/tailscaled+ fmt from compress/flate+ hash from crypto+ - hash/adler32 from compress/zlib hash/crc32 from compress/gzip+ hash/maphash from go4.org/mem html from tailscale.com/ipn/ipnlocal+ - image from github.com/skip2/go-qrcode+ - image/color from github.com/skip2/go-qrcode+ - image/png from github.com/skip2/go-qrcode internal/abi from hash/maphash+ internal/asan from internal/runtime/maps+ internal/bisect from internal/godebug @@ -406,7 +398,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de internal/unsafeheader from internal/reflectlite+ io from bufio+ io/fs from crypto/x509+ - io/ioutil from github.com/skip2/go-qrcode iter from bytes+ log from github.com/klauspost/compress/zstd+ log/internal from log diff --git a/feature/buildfeatures/feature_qrcodes_disabled.go b/feature/buildfeatures/feature_qrcodes_disabled.go new file mode 100644 index 000000000..4b992501c --- /dev/null +++ b/feature/buildfeatures/feature_qrcodes_disabled.go @@ -0,0 +1,13 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +// Code generated by gen.go; DO NOT EDIT. + +//go:build ts_omit_qrcodes + +package buildfeatures + +// HasQRCodes is whether the binary was built with support for modular feature "QR codes in tailscale CLI". +// Specifically, it's whether the binary was NOT built with the "ts_omit_qrcodes" build tag. +// It's a const so it can be used for dead code elimination. +const HasQRCodes = false diff --git a/feature/buildfeatures/feature_qrcodes_enabled.go b/feature/buildfeatures/feature_qrcodes_enabled.go new file mode 100644 index 000000000..5b74e2b3e --- /dev/null +++ b/feature/buildfeatures/feature_qrcodes_enabled.go @@ -0,0 +1,13 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +// Code generated by gen.go; DO NOT EDIT. + +//go:build !ts_omit_qrcodes + +package buildfeatures + +// HasQRCodes is whether the binary was built with support for modular feature "QR codes in tailscale CLI". +// Specifically, it's whether the binary was NOT built with the "ts_omit_qrcodes" build tag. +// It's a const so it can be used for dead code elimination. +const HasQRCodes = true diff --git a/feature/featuretags/featuretags.go b/feature/featuretags/featuretags.go index 44b129576..99df18b5a 100644 --- a/feature/featuretags/featuretags.go +++ b/feature/featuretags/featuretags.go @@ -222,6 +222,7 @@ var Features = map[FeatureTag]FeatureMeta{ Desc: "Linux NetworkManager integration", Deps: []FeatureTag{"dbus"}, }, + "qrcodes": {Sym: "QRCodes", Desc: "QR codes in tailscale CLI"}, "relayserver": {Sym: "RelayServer", Desc: "Relay server"}, "resolved": { Sym: "Resolved", diff --git a/util/qrcodes/format.go b/util/qrcodes/format.go new file mode 100644 index 000000000..dbd565b2e --- /dev/null +++ b/util/qrcodes/format.go @@ -0,0 +1,22 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +package qrcodes + +// Format selects the text representation used to print QR codes. +type Format string + +const ( + // FormatAuto will format QR codes to best fit the capabilities of the + // [io.Writer]. + FormatAuto Format = "auto" + + // FormatASCII will format QR codes with only ASCII characters. + FormatASCII Format = "ascii" + + // FormatLarge will format QR codes with full block characters. + FormatLarge Format = "large" + + // FormatSmall will format QR codes with full and half block characters. + FormatSmall Format = "small" +) diff --git a/util/qrcodes/qrcodes.go b/util/qrcodes/qrcodes.go index 14bdf8581..02e06e59b 100644 --- a/util/qrcodes/qrcodes.go +++ b/util/qrcodes/qrcodes.go @@ -1,6 +1,8 @@ // Copyright (c) Tailscale Inc & AUTHORS // SPDX-License-Identifier: BSD-3-Clause +//go:build !ts_omit_qrcodes + // Package qrcodes provides functions to render or format QR codes. package qrcodes @@ -12,24 +14,6 @@ import ( qrcode "github.com/skip2/go-qrcode" ) -// Format selects the text representation used to print QR codes. -type Format string - -const ( - // FormatAuto will format QR codes to best fit the capabilities of the - // [io.Writer]. - FormatAuto Format = "auto" - - // FormatASCII will format QR codes with only ASCII characters. - FormatASCII Format = "ascii" - - // FormatLarge will format QR codes with full block characters. - FormatLarge Format = "large" - - // FormatSmall will format QR codes with full and half block characters. - FormatSmall Format = "small" -) - // Fprintln formats s according to [Format] and writes a QR code to w, along // with a newline. It returns the number of bytes written and any write error // encountered. diff --git a/util/qrcodes/qrcodes_disabled.go b/util/qrcodes/qrcodes_disabled.go new file mode 100644 index 000000000..fa1b89cf4 --- /dev/null +++ b/util/qrcodes/qrcodes_disabled.go @@ -0,0 +1,16 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +//go:build ts_omit_qrcodes + +package qrcodes + +import "io" + +func Fprintln(w io.Writer, format Format, s string) (n int, err error) { + panic("omitted") +} + +func EncodePNG(s string, size int) ([]byte, error) { + panic("omitted") +} diff --git a/util/qrcodes/qrcodes_linux.go b/util/qrcodes/qrcodes_linux.go index 9cc0c09bf..8f0d40f0a 100644 --- a/util/qrcodes/qrcodes_linux.go +++ b/util/qrcodes/qrcodes_linux.go @@ -1,7 +1,7 @@ // Copyright (c) Tailscale Inc & AUTHORS // SPDX-License-Identifier: BSD-3-Clause -//go:build linux +//go:build linux && !ts_omit_qrcodes package qrcodes diff --git a/util/qrcodes/qrcodes_notlinux.go b/util/qrcodes/qrcodes_notlinux.go index a12ce39d1..3149a6060 100644 --- a/util/qrcodes/qrcodes_notlinux.go +++ b/util/qrcodes/qrcodes_notlinux.go @@ -1,7 +1,7 @@ // Copyright (c) Tailscale Inc & AUTHORS // SPDX-License-Identifier: BSD-3-Clause -//go:build !linux +//go:build !linux && !ts_omit_qrcodes package qrcodes