Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove QR code functionality from CLI #6370

Merged
merged 2 commits into from
Jul 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ For details about compatibility between different releases, see the **Commitment

### Removed

- Command-line interface support for listing QR code formats and generating QR codes. This is considered the responsibility of a LoRaWAN Join Server.

### Fixed

### Security
Expand Down
171 changes: 16 additions & 155 deletions cmd/ttn-lw-cli/commands/end_devices.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ import (
"crypto/rand"
"fmt"
stdio "io"
"mime"
"os"
"path"
"strings"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -832,10 +830,11 @@ var (
}
// TODO: Remove (https://github.com/TheThingsNetwork/lorawan-stack/issues/999)
endDevicesProvisionCommand = &cobra.Command{
Use: "provision",
Short: "Provision end devices using vendor-specific data",
Use: "provision",
Short: "Provision end devices using vendor-specific data (DEPRECATED)",
Hidden: true,
RunE: func(cmd *cobra.Command, args []string) error {
logger.Warn("This command is deprecated. Please use `device template from-data` instead")
logger.Warn("This command is deprecated. Please use The Things Join Server instead")

appID := getApplicationID(cmd.Flags(), nil)
if appID == nil {
Expand Down Expand Up @@ -1137,162 +1136,24 @@ var (
endDevicesListQRCodeFormatsCommand = &cobra.Command{
Use: "list-qr-formats",
Aliases: []string{"ls-qr-formats", "listqrformats", "lsqrformats", "lsqrfmts", "lsqrfmt", "qr-formats"},
Short: "List QR code formats (EXPERIMENTAL)",
Short: "List QR code formats (DEPRECATED)",
Hidden: true,
RunE: func(cmd *cobra.Command, args []string) error {
qrg, err := api.Dial(ctx, config.QRCodeGeneratorGRPCAddress)
if err != nil {
return err
}

res, err := ttnpb.NewEndDeviceQRCodeGeneratorClient(qrg).ListFormats(ctx, ttnpb.Empty)
if err != nil {
return err
}

return io.Write(os.Stdout, config.OutputFormat, res)
return fmt.Errorf(
"this command is no longer supported. Join Servers are responsible for generating QR codes",
)
},
}
endDevicesGenerateQRCommand = &cobra.Command{
Use: "generate-qr [application-id] [device-id]",
Aliases: []string{"genqr"},
Short: "Generate an end device QR code (EXPERIMENTAL)",
Long: `Generate an end device QR code (EXPERIMENTAL)

This command saves a QR code in PNG format in the given folder. The filename is
the device ID.

This command may take end device identifiers from stdin.`,
Example: `
To generate a QR code for a single end device:
$ ttn-lw-cli end-devices generate-qr app1 dev1

To generate a QR code for multiple end devices:
$ ttn-lw-cli end-devices list app1 \
| ttn-lw-cli end-devices generate-qr`,
RunE: asBulk(func(cmd *cobra.Command, args []string) error {
var ids *ttnpb.EndDeviceIdentifiers
if inputDecoder != nil {
var dev ttnpb.EndDevice
if err := inputDecoder.Decode(&dev); err != nil {
return err
}
if dev.GetIds().GetApplicationIds().GetApplicationId() == "" {
return errNoApplicationID.New()
}
if dev.Ids.DeviceId == "" {
return errNoEndDeviceID.New()
}
ids = dev.Ids
} else {
var err error
ids, err = getEndDeviceID(cmd.Flags(), args, true)
if err != nil {
return err
}
}

formatID, _ := cmd.Flags().GetString("format-id")

qrg, err := api.Dial(ctx, config.QRCodeGeneratorGRPCAddress)
if err != nil {
return err
}
client := ttnpb.NewEndDeviceQRCodeGeneratorClient(qrg)
format, err := client.GetFormat(ctx, &ttnpb.GetQRCodeFormatRequest{
FormatId: formatID,
})
if err != nil {
return err
}

isPaths, nsPaths, asPaths, jsPaths := splitEndDeviceGetPaths(format.FieldMask.GetPaths()...)
if len(nsPaths) > 0 {
isPaths = append(isPaths, "network_server_address")
}
if len(asPaths) > 0 {
isPaths = append(isPaths, "application_server_address")
}
if len(jsPaths) > 0 {
isPaths = append(isPaths, "join_server_address")
}

is, err := api.Dial(ctx, config.IdentityServerGRPCAddress)
if err != nil {
return err
}
logger.WithField("paths", isPaths).Debug("Get end device from Identity Server")
device, err := ttnpb.NewEndDeviceRegistryClient(is).Get(ctx, &ttnpb.GetEndDeviceRequest{
EndDeviceIds: ids,
FieldMask: ttnpb.FieldMask(isPaths...),
})
if err != nil {
return err
}

if device.ClaimAuthenticationCode.GetValue() != "" {
// ClaimAuthenticationCode is already retrieved from the IS. We can unset the related JS paths.
jsPaths = ttnpb.ExcludeFields(jsPaths, claimAuthenticationCodePaths...)
}

nsMismatch, asMismatch, jsMismatch := compareServerAddressesEndDevice(device, config)
if len(nsPaths) > 0 && nsMismatch {
return errAddressMismatchEndDevice.New()
}
if len(asPaths) > 0 && asMismatch {
return errAddressMismatchEndDevice.New()
}
if len(jsPaths) > 0 && jsMismatch {
return errAddressMismatchEndDevice.New()
}
dev, err := getEndDevice(device.Ids, nsPaths, asPaths, jsPaths, true)
if err != nil {
return err
}
if err := device.SetFields(dev, append(append(nsPaths, asPaths...), jsPaths...)...); err != nil {
return err
}

if device.ClaimAuthenticationCode.GetValue() == "" {
// Unset the field since qrcodegenerator.Generate does not support fieldmask
// and an empty field would result in a validation error.
device.ClaimAuthenticationCode = nil
}

size, _ := cmd.Flags().GetUint32("size")
res, err := client.Generate(ctx, &ttnpb.GenerateEndDeviceQRCodeRequest{
FormatId: formatID,
EndDevice: device,
Image: &ttnpb.GenerateEndDeviceQRCodeRequest_Image{
ImageSize: size,
},
})
if err != nil {
return err
}

folder, _ := cmd.Flags().GetString("folder")
if folder == "" {
folder, err = os.Getwd()
if err != nil {
return err
}
}

var ext string
if exts, err := mime.ExtensionsByType(res.Image.Embedded.MimeType); err == nil && len(exts) > 0 {
ext = exts[0]
}
filename := path.Join(folder, device.Ids.DeviceId+ext)
if err := os.WriteFile(filename, res.Image.Embedded.Data, 0o644); err != nil { //nolint:gas
return err
}

logger.WithFields(log.Fields(
"value", res.Text,
"filename", filename,
)).Info("Generated QR code")
return nil
}),
Short: "Generate an end device QR code (DEPRECATED)",
Hidden: true,
RunE: func(cmd *cobra.Command, args []string) error {
return fmt.Errorf(
"this command is no longer supported. Join Servers are responsible for generating QR codes",
)
},
}
endDevicesExternalJSCommand = &cobra.Command{
Use: "use-external-join-server [application-id] [device-id]",
Expand Down
Loading