From 6db30a10f7a160efeaeeb955e92569c767ca8b2d Mon Sep 17 00:00:00 2001 From: Simon Law Date: Tue, 16 Sep 2025 15:49:03 -0700 Subject: [PATCH] cmd/tailscale: shrink QR codes using half blocks (#17084) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When running `tailscale up --qr`, the QR code is rendered using two full blocks ██ to form a square pixel. This is a problem for people with smaller terminals, because the output is 37 lines high. All modern terminals support half block characters, like ▀ and ▄, which only takes 19 lines and can easily fit in a regular terminal window. For example, https://login.tailscale.com/a/0123456789 is now rendered: ``` user@host:~$ tailscale up --qr █████████████████████████████████████ █████████████████████████████████████ ████ ▄▄▄▄▄ █ ▀▀ █▄▀▀ ▄ █ ▄▄▄▄▄ ████ ████ █ █ █▀ ▄▄▄█▀█▄▀ ▄█ █ █ ████ ████ █▄▄▄█ ██▄ ▄▀▀▄▄ ▀▀ ▀█ █▄▄▄█ ████ ████▄▄▄▄▄▄▄█ ▀▄▀ █▄▀▄▀▄█ █▄▄▄▄▄▄▄████ ████▄█▄ ▀▄▄▄█▀▄█▀ ▀▄ ▄ ▀▀ ▀▀▄█▄ ████ ████▄▀▄▀▄█▄ █ ▄▄▄▄█▀██▀██▄▄█▀█▄▄▀████ ████▄█▀ ▀ ▄█▄▄▀▄▀█ ▄ ▄█▀█▄▀██▄ ▀▀████ █████▀ ▀ ▄▀▀▀▀▄▀▄▀▀ ▄▄ ▄ ▀ █▄ ▄████ ██████ ▄▄█▄▄▄▄▄▀ █ ▄▀▀▄█▀ █ ▄ ▀ █████ ████▄█▄▄ ▄▀ ▀██▀ ▄█▀▀████▄▀█ ██████ █████▄▄▄█▄▄▄▀▀ █▄▄▄▄▄ ▀█ ▄▄▄ ▀▀████ ████ ▄▄▄▄▄ █ ██▄ ▀ █▀█ ▄ █▄█ █▄█████ ████ █ █ █▀ █ ▀█▄▄ █▀ ▄ ▀▄▀▄████ ████ █▄▄▄█ █▄█▀█▄▀██▀██▄ ▀█▄▀▀▄▀▄████ ████▄▄▄▄▄▄▄█▄▄███▄▄▄███▄▄▄██▄██▄█████ █████████████████████████████████████ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ``` To render a QR code with full blocks, like we did in the past, use the new `--qr-format` flag: ``` user@host:~$ tailscale up --qr --qr-format=large ██████████████████████████████████████████████████████████████████████████ ██████████████████████████████████████████████████████████████████████████ ██████████████████████████████████████████████████████████████████████████ ██████████████████████████████████████████████████████████████████████████ ████████ ██ ████ ██ ████ ██ ████████ ████████ ██████████ ██ ████ ██ ██ ██████████ ████████ ████████ ██ ██ ████ ██████ ██ ██ ██ ██ ████████ ████████ ██ ██ ██ ████████ ████ ████ ██ ██ ████████ ████████ ██ ██ ████ ████ ████ ████ ██ ██ ████████ ████████ ██████████ ██████ ██ ████ ██ ██████████ ████████ ████████ ██ ██ ██ ██ ██ ██ ██ ██ ████████ ████████████████████████ ██ ████ ██ ████ ████████████████████████ ████████ ██ ██ ████ ████ ██ ████ ████ ██ ████████ ██████████████ ████████ ████ ██ ██ ██████ ████████ ████████ ██ ██ ██ ██ ██████████████ ██████ ██████████ ██████████ ██ ██████ ██ ██████████ ████ ██████████ ██████ ████████ ████████ ████ ██ ██ ██ ████ ██████ ██████ ████████████ ████████████ ████████ ██ ██ ██ ████ ████ ██████ ████████ ████████████ ██ ████████ ██ ████ ██ ██ ████████ ██████████ ██ ██ ██ ████ ██ ████ ██████████ ████████████ ██ ██ ██ ████ ████ ██ ██ ██████████ ████████████ ████████████████ ██ ██ ████ ██ ██ ██████████ ████████ ██ ██ ████████ ██████████████ ████ ████████████ ████████████████ ██ ████ ████ ██████████ ██ ████████████ ██████████ ██ ████ ██ ████ ████████████ ████████████████████████ ████████████ ██ ██████ ████████ ████████ ██ ████ ██ ██████ ██ ██ ██ ██████████ ████████ ██████████ ██ ██████ ██ ██ ██ ██████ ██████████████ ████████ ██ ██ ████ ██ ████ ████ ██ ██ ████████ ████████ ██ ██ ██ ██ ██████ ██ ██ ██ ██████████ ████████ ██ ██ ██ ██████ ████████████ ████ ████ ██ ████████ ████████ ██████████ ██████ ████ ████ ██████ ████ ██ ██████████ ████████ ██ ██████ ██████ ████ ████ ██████████ ██████████████████████████████████████████████████████████████████████████ ██████████████████████████████████████████████████████████████████████████ ██████████████████████████████████████████████████████████████████████████ ██████████████████████████████████████████████████████████████████████████ ``` Fixes #17083 Signed-off-by: Simon Law --- cmd/tailscale/cli/up.go | 13 +++++++++++-- cmd/tailscale/cli/up_test.go | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/cmd/tailscale/cli/up.go b/cmd/tailscale/cli/up.go index 097af725b..c78a63569 100644 --- a/cmd/tailscale/cli/up.go +++ b/cmd/tailscale/cli/up.go @@ -95,6 +95,7 @@ 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", "small", "QR code formatting (small or large)") 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.server, "login-server", ipn.DefaultControlURL, "base URL of control server") @@ -164,6 +165,7 @@ func defaultNetfilterMode() string { // added to it. Add new arguments to setArgsT instead. type upArgsT struct { qr bool + qrFormat string reset bool server string acceptRoutes bool @@ -658,7 +660,14 @@ func runUp(ctx context.Context, cmd string, args []string, upArgs upArgsT) (retE if err != nil { log.Printf("QR code error: %v", err) } else { - fmt.Fprintf(Stderr, "%s\n", q.ToString(false)) + switch upArgs.qrFormat { + case "large": + fmt.Fprintf(Stderr, "%s\n", q.ToString(false)) + case "small": + fmt.Fprintf(Stderr, "%s\n", q.ToSmallString(false)) + default: + log.Printf("unknown QR code format: %q", upArgs.qrFormat) + } } } } @@ -805,7 +814,7 @@ func addPrefFlagMapping(flagName string, prefNames ...string) { // correspond to an ipn.Pref. func preflessFlag(flagName string) bool { switch flagName { - case "auth-key", "force-reauth", "reset", "qr", "json", "timeout", "accept-risk", "host-routes": + case "auth-key", "force-reauth", "reset", "qr", "qr-format", "json", "timeout", "accept-risk", "host-routes": return true } return false diff --git a/cmd/tailscale/cli/up_test.go b/cmd/tailscale/cli/up_test.go index eb06f84dc..efddb5324 100644 --- a/cmd/tailscale/cli/up_test.go +++ b/cmd/tailscale/cli/up_test.go @@ -35,6 +35,7 @@ var validUpFlags = set.Of( "operator", "report-posture", "qr", + "qr-format", "reset", "shields-up", "snat-subnet-routes",