Skip to content
Open
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
11 changes: 6 additions & 5 deletions wire-ios-utilities/Source/NSUserDefaults+SharedUserDefaults.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#import <CommonCrypto/CommonCrypto.h>


NSString * const ZMCookieKeyKey = @"ZMCookieKey";

@implementation NSUserDefaults (SharedUserDefaults)

+ (NSString *)groupName
Expand All @@ -43,18 +45,17 @@ + (instancetype)sharedUserDefaults

+ (NSData *)cookiesKey
{
static NSString * const CookieKeyKey = @"ZMCookieKey";
NSUserDefaults *sharedDefaults = [NSUserDefaults sharedUserDefaults];
NSData *key = [sharedDefaults dataForKey:CookieKeyKey];
NSData *key = [sharedDefaults dataForKey:ZMCookieKeyKey];
if (key == nil) {

#if TARGET_OS_IPHONE
//On older versions we stored key in standard user defaults.
//We need to check for key there first and save it to shared defaults.
//This way extension can use it to decrypt cookies stored in keychain
key = [[NSUserDefaults standardUserDefaults] dataForKey:CookieKeyKey];
key = [[NSUserDefaults standardUserDefaults] dataForKey:ZMCookieKeyKey];
if (key != nil) {
[[NSUserDefaults standardUserDefaults] removeObjectForKey:CookieKeyKey];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:ZMCookieKeyKey];
}
else {
#endif
Expand All @@ -68,7 +69,7 @@ + (NSData *)cookiesKey
}
#endif

[sharedDefaults setObject:key forKey:CookieKeyKey];
[sharedDefaults setObject:key forKey:ZMCookieKeyKey];
}
return key;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

#import <Foundation/Foundation.h>


extern NSString * const ZMCookieKeyKey;

@interface NSUserDefaults (SharedUserDefaults)

Expand Down
31 changes: 31 additions & 0 deletions wire-ios-utilities/Source/UserDefaults+Shared.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// Wire
// Copyright (C) 2026 Wire Swiss GmbH
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.
//

import Foundation

public extension UserDefaults {

/// Returns the `UserDefaults.cookiesKey()` if created and accessible. Unlike `UserDefaults.cookiesKey()`, this
/// property will not attempt to create the key.
static var existingCookiesKey: Data? {
guard let defaults = UserDefaults.shared() else { return nil }

return defaults.data(forKey: ZMCookieKeyKey)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,8 @@ @interface NSUserDefaults_SharedUserDefaultsTests : XCTestCase

@implementation NSUserDefaults_SharedUserDefaultsTests

static NSString *const cookiesKey = @"ZMCookieKey";

- (void)tearDown {
[[NSUserDefaults sharedUserDefaults] removeObjectForKey:cookiesKey];
[[NSUserDefaults sharedUserDefaults] removeObjectForKey:ZMCookieKeyKey];
[super tearDown];
}

Expand Down Expand Up @@ -105,7 +103,7 @@ - (void)testThatItCreatesNewKeyIfNoKeyFoundInDefaults
{
//given
NSData *key1 = [NSUserDefaults cookiesKey];
[[NSUserDefaults sharedUserDefaults] removeObjectForKey:cookiesKey];
[[NSUserDefaults sharedUserDefaults] removeObjectForKey:ZMCookieKeyKey];

//when
NSData *key2 = [NSUserDefaults cookiesKey];
Expand All @@ -121,8 +119,8 @@ - (void)testThatItMovesCookiesFromStandardDefaultsToSharedDefaults
//given
NSData *key1 = [NSUserDefaults cookiesKey];

[[NSUserDefaults standardUserDefaults] setObject:key1 forKey:cookiesKey];
[[NSUserDefaults sharedUserDefaults] removeObjectForKey:cookiesKey];
[[NSUserDefaults standardUserDefaults] setObject:key1 forKey:ZMCookieKeyKey];
[[NSUserDefaults sharedUserDefaults] removeObjectForKey:ZMCookieKeyKey];

//when
NSData *key2 = [NSUserDefaults cookiesKey];
Expand All @@ -131,10 +129,10 @@ - (void)testThatItMovesCookiesFromStandardDefaultsToSharedDefaults
//then

//key should be removed from standard user defaults
XCTAssertNil([[NSUserDefaults standardUserDefaults] objectForKey:cookiesKey]);
XCTAssertNil([[NSUserDefaults standardUserDefaults] objectForKey:ZMCookieKeyKey]);

//key should be stored in shared user defaults
XCTAssertEqualObjects([[NSUserDefaults sharedUserDefaults] objectForKey:cookiesKey], key1);
XCTAssertEqualObjects([[NSUserDefaults sharedUserDefaults] objectForKey:ZMCookieKeyKey], key1);
}
#endif

Expand Down
45 changes: 45 additions & 0 deletions wire-ios-utilities/Tests/Source/UserDefaults+Shared.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// Wire
// Copyright (C) 2026 Wire Swiss GmbH
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.
//

import Testing

@testable import WireUtilities

@Suite(.serialized)
final class UserDefaults_SharedTests {

Check warning on line 24 in wire-ios-utilities/Tests/Source/UserDefaults+Shared.swift

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Rename class "UserDefaults_SharedTests" to match the regular expression ^[A-Z][a-zA-Z0-9]*$.

See more on https://sonarcloud.io/project/issues?id=wireapp_wire-ios&issues=AZ5AV0k_k0uZeavvZ9sK&open=AZ5AV0k_k0uZeavvZ9sK&pullRequest=4734

deinit {
UserDefaults.shared().removeObject(forKey: ZMCookieKeyKey)
}

@Test()
func `existingCookiesKey defaults to nil`() {

Check warning on line 31 in wire-ios-utilities/Tests/Source/UserDefaults+Shared.swift

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove backticks (`) from "existingCookiesKey defaults to nil" and rename it.

See more on https://sonarcloud.io/project/issues?id=wireapp_wire-ios&issues=AZ5AV0k_k0uZeavvZ9sL&open=AZ5AV0k_k0uZeavvZ9sL&pullRequest=4734
// Given, When, Then
#expect(UserDefaults.existingCookiesKey == nil)
}

@Test()
func `existingCookiesKey returns cookiesKey if set`() throws {

Check warning on line 37 in wire-ios-utilities/Tests/Source/UserDefaults+Shared.swift

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove backticks (`) from "existingCookiesKey returns cookiesKey if set" and rename it.

See more on https://sonarcloud.io/project/issues?id=wireapp_wire-ios&issues=AZ5AV0k_k0uZeavvZ9sM&open=AZ5AV0k_k0uZeavvZ9sM&pullRequest=4734
// Given
let key = try #require(UserDefaults.cookiesKey()) // This call creates the key in UserDefaults

// When, Then
#expect(UserDefaults.existingCookiesKey == key)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ final class NotificationService: UNNotificationServiceExtension {
return nil
}

guard let cookiesKey = UserDefaults.existingCookiesKey else {
WireLogger.notifications.warn(
"no cookie encryption key, not loading service",
attributes: .safePublic
)
return nil
}

WireLogger.notifications.info(
"loading new notification service",
attributes: .safePublic
Expand All @@ -114,7 +122,7 @@ final class NotificationService: UNNotificationServiceExtension {
currentBuildNumber: currentBuildNumber,
appContainerURL: appContainerURL,
sharedUserDefaults: sharedUserDefaults,
cookieEncryptionKey: UserDefaults.cookiesKey(),
cookieEncryptionKey: cookiesKey,
minTLSVersion: SecurityFlags.minTLSVersion.stringValue,
preferredAPIVersion: BackendInfo.preferredAPIVersion.map {
UInt($0.rawValue)
Expand Down
Loading