Repository: electron/electron
Pull request: fix: -Wunsafe-buffer-usage warning in didRegisterForRemoteNotificationsWithDeviceToken

#### Description of Change

Part 21 in a [series](https://github.com/electron/electron/pull/43477) to fix `-Wunsafe-buffer-usage` warnings in `shell/`.  This is similar to the fix in #44127 which added an NSData getter helper, so this PR moves that helper into a public header so that it can be used for this fix, too.

#### Checklist

- [x] PR description included and stakeholders cc'd
- [x] `npm test` passes
- [x] [PR release notes](https://github.com/electron/clerk/blob/main/README.md) describe the change in a way relevant to app developers, and are [capitalized, punctuated, and past tense](https://github.com/electron/clerk/blob/main/README.md#examples).

#### Release Notes

Notes: none.

Changed files:
filename: filenames.gni
patch: @@ -205,6 +205,8 @@ filenames = {
     "shell/common/mac/main_application_bundle.mm",
     "shell/common/mac/codesign_util.cc",
     "shell/common/mac/codesign_util.h",
+    "shell/common/mac_util.h",
+    "shell/common/mac_util.mm",
     "shell/common/node_bindings_mac.cc",
     "shell/common/node_bindings_mac.h",
     "shell/common/platform_util_mac.mm",

filename: shell/browser/mac/electron_application_delegate.mm
patch: @@ -10,11 +10,13 @@
 #include "base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim.h"
 #include "base/functional/callback.h"
 #include "base/mac/mac_util.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/sys_string_conversions.h"
 #include "shell/browser/api/electron_api_push_notifications.h"
 #include "shell/browser/browser.h"
 #include "shell/browser/mac/dict_util.h"
 #import "shell/browser/mac/electron_application.h"
+#include "shell/common/mac_util.h"
 
 #import <UserNotifications/UserNotifications.h>
 
@@ -176,18 +178,10 @@ - (IBAction)newWindowForTab:(id)sender {
 
 - (void)application:(NSApplication*)application
     didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {
-  // https://stackoverflow.com/a/16411517
-  const char* token_data = static_cast<const char*>(deviceToken.bytes);
-  NSMutableString* token_string = [NSMutableString string];
-  for (NSUInteger i = 0; i < deviceToken.length; i++) {
-    [token_string appendFormat:@"%02.2hhX", token_data[i]];
-  }
   // Resolve outstanding APNS promises created during registration attempts
-  electron::api::PushNotifications* push_notifications =
-      electron::api::PushNotifications::Get();
-  if (push_notifications) {
+  if (auto* push_notifications = electron::api::PushNotifications::Get()) {
     push_notifications->ResolveAPNSPromiseSetWithToken(
-        base::SysNSStringToUTF8(token_string));
+        base::HexEncode(electron::util::as_byte_span(deviceToken)));
   }
 }
 

filename: shell/common/api/electron_api_native_image_mac.mm
patch: @@ -19,26 +19,14 @@
 #include "gin/handle.h"
 #include "shell/common/gin_converters/image_converter.h"
 #include "shell/common/gin_helper/promise.h"
+#include "shell/common/mac_util.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/image/image_skia_operations.h"
 
 namespace electron::api {
 
-namespace {
-
-base::span<const uint8_t> as_byte_span(NSData* data) {
-  // SAFETY: There is no NSData API that passes the UNSAFE_BUFFER_USAGE
-  // test, so let's isolate the unsafe API use into this function. Instead of
-  // calling '[data bytes]' and '[data length]' directly, the rest of our
-  // code should prefer to use spans returned by this function.
-  return UNSAFE_BUFFERS(base::span{
-      reinterpret_cast<const uint8_t*>([data bytes]), [data length]});
-}
-
-}  // namespace
-
 NSData* bufferFromNSImage(NSImage* image) {
   CGImageRef ref = [image CGImageForProposedRect:nil context:nil hints:nil];
   NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] initWithCGImage:ref];
@@ -140,7 +128,8 @@ void ReceivedThumbnailResult(CGSize size,
     NSData* png_data = bufferFromNSImage(image);
 
     if (args->GetNext(&hsl_shift) && hsl_shift.size() == 3) {
-      auto gfx_image = gfx::Image::CreateFrom1xPNGBytes(as_byte_span(png_data));
+      auto gfx_image = gfx::Image::CreateFrom1xPNGBytes(
+          electron::util::as_byte_span(png_data));
       color_utils::HSL shift = {safeShift(hsl_shift[0], -1),
                                 safeShift(hsl_shift[1], 0.5),
                                 safeShift(hsl_shift[2], 0.5)};
@@ -150,7 +139,8 @@ void ReceivedThumbnailResult(CGSize size,
               .AsNSImage());
     }
 
-    return CreateFromPNG(args->isolate(), as_byte_span(png_data));
+    return CreateFromPNG(args->isolate(),
+                         electron::util::as_byte_span(png_data));
   }
 }
 

filename: shell/common/mac_util.h
patch: @@ -0,0 +1,18 @@
+// Copyright (c) 2024 Microsoft, Inc.
+// Use of this source code is governed by the MIT license that can be
+// found in the LICENSE file.
+
+#ifndef ELECTRON_SHELL_MAC_UTIL_H_
+#define ELECTRON_SHELL_MAC_UTIL_H_
+
+#include "base/containers/span.h"
+
+@class NSData;
+
+namespace electron::util {
+
+base::span<const uint8_t> as_byte_span(NSData* data);
+
+}  // namespace electron::util
+
+#endif  // ELECTRON_SHELL_MAC_UTIL_H_

filename: shell/common/mac_util.mm
patch: @@ -0,0 +1,20 @@
+// Copyright (c) 2024 Microsoft, Inc.
+// Use of this source code is governed by the MIT license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/containers/span.h"
+
+namespace electron::util {
+
+base::span<const uint8_t> as_byte_span(NSData* data) {
+  // SAFETY: There is no NSData API that passes the UNSAFE_BUFFER_USAGE
+  // test, so let's isolate the unsafe API use into this function. Instead of
+  // calling '[data bytes]' and '[data length]' directly, the rest of our
+  // code should prefer to use spans returned by this function.
+  return UNSAFE_BUFFERS(base::span{
+      reinterpret_cast<const uint8_t*>([data bytes]), [data length]});
+}
+
+}  // namespace electron::util