Merge pull request #152 from loki-project/push-notifications

Improved Push Notifications Stage 2
pull/156/head
Niels Andriesse 5 years ago committed by GitHub
commit 657ba22239
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>LokiPushNotificationService</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.usernotifications.service</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).NotificationService</string>
</dict>
</dict>
</plist>

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.loki-project.loki-messenger</string>
</array>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)com.loki-project.loki-messenger</string>
</array>
</dict>
</plist>

@ -0,0 +1,206 @@
import UserNotifications
import SignalServiceKit
import SignalMessaging
final class NotificationService : UNNotificationServiceExtension {
static let isFromRemoteKey = "remote"
static let threadIdKey = "Signal.AppNotificationsUserInfoKey.threadId"
private var didPerformSetup = false
var areVersionMigrationsComplete = false
var contentHandler: ((UNNotificationContent) -> Void)?
var notificationContent: UNMutableNotificationContent?
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
notificationContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
DispatchQueue.main.sync { self.setUpIfNecessary() }
if let notificationContent = notificationContent {
// Modify the notification content here...
let base64EncodedData = notificationContent.userInfo["ENCRYPTED_DATA"] as! String
let data = Data(base64Encoded: base64EncodedData)!
let envelope = try? LokiMessageWrapper.unwrap(data: data)
let envelopeData = try? envelope?.serializedData()
let decrypter = SSKEnvironment.shared.messageDecrypter
if (envelope != nil && envelopeData != nil) {
decrypter.decryptEnvelope(envelope!,
envelopeData: envelopeData!,
successBlock: { result, transaction in
if (try? SSKProtoEnvelope.parseData(result.envelopeData)) != nil {
self.handleDecryptionResult(result: result, notificationContent: notificationContent, transaction: transaction)
} else {
self.completeWithFailure(content: notificationContent)
}
},
failureBlock: {
self.completeWithFailure(content: notificationContent)
}
)
} else {
self.completeWithFailure(content: notificationContent)
}
}
}
func handleDecryptionResult(result: OWSMessageDecryptResult, notificationContent: UNMutableNotificationContent, transaction: YapDatabaseReadWriteTransaction) {
let contentProto = try? SSKProtoContent.parseData(result.plaintextData!)
var thread: TSThread
var newNotificationBody = ""
let masterHexEncodedPublicKey = OWSPrimaryStorage.shared().getMasterHexEncodedPublicKey(for: result.source, in: transaction) ?? result.source
var displayName = masterHexEncodedPublicKey
if let groupID = contentProto?.dataMessage?.group?.id {
thread = TSGroupThread.getOrCreateThread(withGroupId: groupID, groupType: .closedGroup, transaction: transaction)
displayName = thread.name()
if displayName.count < 1 {
displayName = MessageStrings.newGroupDefaultTitle
}
let group: SSKProtoGroupContext = (contentProto?.dataMessage?.group!)!
let oldGroupModel = (thread as! TSGroupThread).groupModel
var removeMembers = Set(arrayLiteral: oldGroupModel.groupMemberIds)
let newGroupModel = TSGroupModel.init(title: group.name,
memberIds:group.members,
image: oldGroupModel.groupImage,
groupId: group.id,
groupType: oldGroupModel.groupType,
adminIds: group.admins)
removeMembers.subtract(Set(arrayLiteral: newGroupModel.groupMemberIds))
newGroupModel.removedMembers = removeMembers as! NSMutableSet
switch contentProto?.dataMessage?.group?.type {
case .update:
newNotificationBody = oldGroupModel.getInfoStringAboutUpdate(to: newGroupModel, contactsManager: SSKEnvironment.shared.contactsManager)
break
case .quit:
let nameString = SSKEnvironment.shared.contactsManager.displayName(forPhoneIdentifier: masterHexEncodedPublicKey, transaction: transaction)
newNotificationBody = NSLocalizedString("GROUP_MEMBER_LEFT", comment: nameString)
break
default:
break
}
} else {
thread = TSContactThread.getOrCreateThread(withContactId: result.source, transaction: transaction)
displayName = contentProto?.dataMessage?.profile?.displayName ?? displayName
}
let userInfo: [String:Any] = [ NotificationService.threadIdKey : thread.uniqueId!, NotificationService.isFromRemoteKey : true ]
notificationContent.title = displayName
notificationContent.userInfo = userInfo
notificationContent.badge = 1
if newNotificationBody.count < 1 {
newNotificationBody = contentProto?.dataMessage?.body ?? ""
}
notificationContent.body = newNotificationBody
if notificationContent.body.count < 1 {
self.completeWithFailure(content: notificationContent)
} else {
self.contentHandler!(notificationContent)
}
}
func setUpIfNecessary() {
AssertIsOnMainThread()
// The NSE will often re-use the same process, so if we're
// already set up we want to do nothing; we're already ready
// to process new messages.
guard !didPerformSetup else { return }
didPerformSetup = true
// This should be the first thing we do.
SetCurrentAppContext(NotificationServiceExtensionContext())
DebugLogger.shared().enableTTYLogging()
if _isDebugAssertConfiguration() {
DebugLogger.shared().enableFileLogging()
}
Logger.info("")
_ = AppVersion.sharedInstance()
Cryptography.seedRandom()
// We should never receive a non-voip notification on an app that doesn't support
// app extensions since we have to inform the service we wanted these, so in theory
// this path should never occur. However, the service does have our push token
// so it is possible that could change in the future. If it does, do nothing
// and don't disturb the user. Messages will be processed when they open the app.
guard OWSPreferences.isReadyForAppExtensions() else { return completeSilenty() }
AppSetup.setupEnvironment(
appSpecificSingletonBlock: {
// TODO: calls..
SSKEnvironment.shared.callMessageHandler = NoopCallMessageHandler()
SSKEnvironment.shared.notificationsManager = NoopNotificationsManager()
},
migrationCompletion: { [weak self] in
self?.versionMigrationsDidComplete()
}
)
NotificationCenter.default.addObserver(self,
selector: #selector(storageIsReady),
name: .StorageIsReady,
object: nil)
}
override func serviceExtensionTimeWillExpire() {
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
if let contentHandler = contentHandler, let notificationContent = notificationContent {
contentHandler(notificationContent)
}
}
func wasReceivedByUD(envelope: SSKProtoEnvelope) -> Bool {
return (envelope.type == .unidentifiedSender && (!envelope.hasSource || envelope.source!.count < 1))
}
@objc
func versionMigrationsDidComplete() {
AssertIsOnMainThread()
Logger.debug("")
areVersionMigrationsComplete = true
checkIsAppReady()
}
@objc
func storageIsReady() {
AssertIsOnMainThread()
Logger.debug("")
checkIsAppReady()
}
@objc
func checkIsAppReady() {
AssertIsOnMainThread()
// Only mark the app as ready once.
guard !AppReadiness.isAppReady() else { return }
// App isn't ready until storage is ready AND all version migrations are complete.
guard OWSStorage.isStorageReady() && areVersionMigrationsComplete else { return }
// Note that this does much more than set a flag; it will also run all deferred blocks.
AppReadiness.setAppIsReady()
}
func completeSilenty() {
contentHandler?(.init())
}
func completeWithFailure(content: UNMutableNotificationContent) {
content.body = "You've got a new message."
content.title = "Session"
let userInfo: [String:Any] = [NotificationService.isFromRemoteKey : true]
content.userInfo = userInfo
contentHandler?(content)
}
}

@ -0,0 +1,94 @@
//
// Copyright (c) 2020 Open Whisper Systems. All rights reserved.
//
import Foundation
import SignalServiceKit
import SignalMessaging
class NotificationServiceExtensionContext: NSObject, AppContext {
var wasWokenUpBySilentPushNotification: Bool = true
var openSystemSettingsAction: UIAlertAction?
let isMainApp = false
let isMainAppAndActive = false
func isInBackground() -> Bool { true }
func isAppForegroundAndActive() -> Bool { false }
func mainApplicationStateOnLaunch() -> UIApplication.State { .inactive }
var shouldProcessIncomingMessages: Bool { true }
func canPresentNotifications() -> Bool { true }
let appLaunchTime = Date()
lazy var buildTime: Date = {
guard let buildTimestamp = Bundle.main.object(forInfoDictionaryKey: "BuildTimestamp") as? TimeInterval, buildTimestamp > 0 else {
Logger.debug("No build timestamp, assuming app never expires.")
return .distantFuture
}
return .init(timeIntervalSince1970: buildTimestamp)
}()
func keychainStorage() -> SSKKeychainStorage {
return SSKDefaultKeychainStorage.shared
}
func appDocumentDirectoryPath() -> String {
guard let documentDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last else {
owsFail("failed to query document directory")
}
return documentDirectoryURL.path
}
func appSharedDataDirectoryPath() -> String {
guard let groupContainerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: SignalApplicationGroup) else {
owsFail("failed to query group container")
}
return groupContainerURL.path
}
func appDatabaseBaseDirectoryPath() -> String {
return appSharedDataDirectoryPath()
}
func appUserDefaults() -> UserDefaults {
guard let userDefaults = UserDefaults(suiteName: SignalApplicationGroup) else {
owsFail("failed to initialize user defaults")
}
return userDefaults
}
override init() { super.init() }
// MARK: - Unused in this extension
let isRTL = false
let isRunningTests = false
var mainWindow: UIWindow?
let frame: CGRect = .zero
let interfaceOrientation: UIInterfaceOrientation = .unknown
let reportedApplicationState: UIApplication.State = .background
let statusBarHeight: CGFloat = .zero
func beginBackgroundTask(expirationHandler: @escaping BackgroundTaskExpirationHandler) -> UInt { 0 }
func endBackgroundTask(_ backgroundTaskIdentifier: UInt) {}
func beginBackgroundTask(expirationHandler: @escaping BackgroundTaskExpirationHandler) -> UIBackgroundTaskIdentifier { .invalid }
func endBackgroundTask(_ backgroundTaskIdentifier: UIBackgroundTaskIdentifier) {}
func ensureSleepBlocking(_ shouldBeBlocking: Bool, blockingObjectsDescription: String) {}
func setMainAppBadgeNumber(_ value: Int) {}
func setStatusBarHidden(_ isHidden: Bool, animated isAnimated: Bool) {}
func frontmostViewController() -> UIViewController? { nil }
func setNetworkActivityIndicatorVisible(_ value: Bool) {}
func runNowOr(whenMainAppIsActive block: @escaping AppActiveBlock) {}
func ensureSleepBlocking(_ shouldBeBlocking: Bool, blockingObjects: [Any]) {}
}

@ -22,7 +22,8 @@ def shared_pods
pod 'Curve25519Kit', git: 'https://github.com/signalapp/Curve25519Kit', testspecs: ["Tests"]
# pod 'Curve25519Kit', path: '../Curve25519Kit', testspecs: ["Tests"]
pod 'SignalMetadataKit', git: 'https://github.com/signalapp/SignalMetadataKit', testspecs: ["Tests"]
# Don't update SignalMetadataKit. There's some Loki specific stuff in there that gets overwritten otherwise.
# pod 'SignalMetadataKit', git: 'https://github.com/signalapp/SignalMetadataKit', testspecs: ["Tests"]
# pod 'SignalMetadataKit', path: '../SignalMetadataKit', testspecs: ["Tests"]
pod 'SignalServiceKit', path: '.', testspecs: ["Tests"]
@ -88,6 +89,12 @@ target 'SignalShareExtension' do
shared_pods
end
target 'LokiPushNotificationService' do
project 'Signal'
pod 'CryptoSwift', '~> 1.0', :inhibit_warnings => true
shared_pods
end
target 'SignalMessaging' do
project 'Signal'
shared_pods

@ -60,7 +60,6 @@ PODS:
- Mantle (2.1.0):
- Mantle/extobjc (= 2.1.0)
- Mantle/extobjc (2.1.0)
- Mixpanel (3.4.7)
- NVActivityIndicatorView (4.7.0):
- NVActivityIndicatorView/Presenter (= 4.7.0)
- NVActivityIndicatorView/Presenter (4.7.0)
@ -220,7 +219,6 @@ DEPENDENCIES:
- HKDFKit (from `https://github.com/signalapp/HKDFKit.git`)
- HKDFKit/Tests (from `https://github.com/signalapp/HKDFKit.git`)
- Mantle (from `https://github.com/signalapp/Mantle`, branch `signal-master`)
- Mixpanel (~> 3.4)
- NVActivityIndicatorView (~> 4.7)
- PromiseKit (= 6.5.3)
- PureLayout
@ -238,7 +236,7 @@ DEPENDENCIES:
- YYImage
SPEC REPOS:
https://github.com/cocoapods/specs.git:
https://github.com/CocoaPods/Specs.git:
- AFNetworking
- CocoaLumberjack
- Crashlytics
@ -249,7 +247,6 @@ SPEC REPOS:
- GCDWebServer
- GoogleUtilities
- libPhoneNumber-iOS
- Mixpanel
- NVActivityIndicatorView
- PromiseKit
- PureLayout
@ -331,7 +328,6 @@ SPEC CHECKSUMS:
HKDFKit: 3b6dbbb9d59c221cc6c52c3aa915700cbf24e376
libPhoneNumber-iOS: e444379ac18bbfbdefad571da735b2cd7e096caa
Mantle: 2fa750afa478cd625a94230fbf1c13462f29395b
Mixpanel: 696e0a1c7f2685aa06bb23829b7a58ab7203d6c7
NVActivityIndicatorView: b19ddab2576f805cbe0fb2306cba3476e09a1dea
PromiseKit: c609029bdd801f792551a504c695c7d3098b42cd
PureLayout: f08c01b8dec00bb14a1fefa3de4c7d9c265df85e
@ -339,7 +335,7 @@ SPEC CHECKSUMS:
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
SignalCoreKit: c2d8132cdedb95d35eb2f8ae7eac0957695d0a8b
SignalMetadataKit: 6fa5e9a53c7f104568662521a2f3874672ff7a02
SignalServiceKit: 102576f58e17a5fe3093899adce7e7c192a7bee0
SignalServiceKit: 5c5b63a39d5054201ab59ef6daf0fa0a1a0c7887
SQLCipher: efbdb52cdbe340bcd892b1b14297df4e07241b7f
SSZipArchive: 8e859da2520142e09166bc9161967db296e9d02f
Starscream: ef3ece99d765eeccb67de105bfa143f929026cf5
@ -347,6 +343,6 @@ SPEC CHECKSUMS:
YapDatabase: b418a4baa6906e8028748938f9159807fd039af4
YYImage: 1e1b62a9997399593e4b9c4ecfbbabbf1d3f3b54
PODFILE CHECKSUM: 156b349e2791f53224143291e318592b9c1f7ade
PODFILE CHECKSUM: 472252f3a4801d0d14d9553ff33cf52ef0846dc3
COCOAPODS: 1.5.3
COCOAPODS: 1.9.0

@ -1 +1 @@
Subproject commit a47226784f77a40a1f82364fdce27354f05e56cf
Subproject commit e1846369c87557efc66f7994c5e7d924e707e579

@ -331,6 +331,7 @@
34EA69422194DE8000702471 /* MediaUploadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EA69412194DE7F00702471 /* MediaUploadView.swift */; };
34F308A21ECB469700BB7697 /* OWSBezierPathView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34F308A11ECB469700BB7697 /* OWSBezierPathView.m */; };
34FDB29221FF986600A01202 /* UIView+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34FDB29121FF986600A01202 /* UIView+OWS.swift */; };
390650A6D345BFE01E006DB0 /* Pods_LokiPushNotificationService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04912E453971FB16E5E78EC6 /* Pods_LokiPushNotificationService.framework */; };
4503F1BE20470A5B00CEE724 /* classic-quiet.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 4503F1BB20470A5B00CEE724 /* classic-quiet.aifc */; };
4503F1BF20470A5B00CEE724 /* classic.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 4503F1BC20470A5B00CEE724 /* classic.aifc */; };
4503F1C3204711D300CEE724 /* OWS107LegacySounds.m in Sources */ = {isa = PBXBuildFile; fileRef = 4503F1C1204711D200CEE724 /* OWS107LegacySounds.m */; };
@ -519,6 +520,11 @@
768A1A2B17FC9CD300E00ED8 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 768A1A2A17FC9CD300E00ED8 /* libz.dylib */; };
76C87F19181EFCE600C4ACAB /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 76C87F18181EFCE600C4ACAB /* MediaPlayer.framework */; };
76EB054018170B33006006FC /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 76EB03C318170B33006006FC /* AppDelegate.m */; };
7BC01A3E241F40AB00BC7C55 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BC01A3D241F40AB00BC7C55 /* NotificationService.swift */; };
7BC01A42241F40AB00BC7C55 /* LokiPushNotificationService.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 7BC01A3B241F40AB00BC7C55 /* LokiPushNotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
7BDCFC08242186E700641C39 /* NotificationServiceExtensionContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDCFC07242186E700641C39 /* NotificationServiceExtensionContext.swift */; };
7BDCFC092421894900641C39 /* MessageFetcherJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 452ECA4C1E087E7200E2F016 /* MessageFetcherJob.swift */; };
7BDCFC0B2421EB7600641C39 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B6F509951AA53F760068F56A /* Localizable.strings */; };
954AEE6A1DF33E01002E5410 /* ContactsPickerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 954AEE681DF33D32002E5410 /* ContactsPickerTest.swift */; };
A10FDF79184FB4BB007FF963 /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 76C87F18181EFCE600C4ACAB /* MediaPlayer.framework */; };
A11CD70D17FA230600A2D1B1 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A11CD70C17FA230600A2D1B1 /* QuartzCore.framework */; };
@ -577,7 +583,6 @@
B83F2B88240CB75A000A54AB /* UIImage+Scaling.swift in Sources */ = {isa = PBXBuildFile; fileRef = B83F2B87240CB75A000A54AB /* UIImage+Scaling.swift */; };
B846365B22B7418B00AF1514 /* Identicon+ObjC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B846365A22B7418B00AF1514 /* Identicon+ObjC.swift */; };
B84664F5235022F30083A1CD /* MentionUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84664F4235022F30083A1CD /* MentionUtilities.swift */; };
B847570323D5698100759540 /* LokiPushNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B847570223D5698100759540 /* LokiPushNotificationManager.swift */; };
B85357BF23A1AE0800AAF6CD /* SeedReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85357BE23A1AE0800AAF6CD /* SeedReminderView.swift */; };
B85357C123A1B81900AAF6CD /* SeedReminderViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85357C023A1B81900AAF6CD /* SeedReminderViewDelegate.swift */; };
B85357C323A1BD1200AAF6CD /* SeedVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85357C223A1BD1200AAF6CD /* SeedVC.swift */; };
@ -678,6 +683,13 @@
remoteGlobalIDString = 453518911FC63DBF00210559;
remoteInfo = SignalMessaging;
};
7BC01A40241F40AB00BC7C55 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D221A080169C9E5E00537ABF /* Project object */;
proxyType = 1;
remoteGlobalIDString = 7BC01A3A241F40AB00BC7C55;
remoteInfo = LokiPushNotificationService;
};
B6AFCEBA19A93DA60098CFCB /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D221A080169C9E5E00537ABF /* Project object */;
@ -694,6 +706,7 @@
dstPath = "";
dstSubfolderSpec = 13;
files = (
7BC01A42241F40AB00BC7C55 /* LokiPushNotificationService.appex in Embed App Extensions */,
453518721FC635DD00210559 /* SignalShareExtension.appex in Embed App Extensions */,
);
name = "Embed App Extensions";
@ -713,7 +726,9 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
04912E453971FB16E5E78EC6 /* Pods_LokiPushNotificationService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LokiPushNotificationService.framework; sourceTree = BUILT_PRODUCTS_DIR; };
0F94C85CB0B235DA37F68ED0 /* Pods_SignalShareExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SignalShareExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; };
18D19142FD6E60FD0A5D89F7 /* Pods-LokiPushNotificationService.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LokiPushNotificationService.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-LokiPushNotificationService/Pods-LokiPushNotificationService.app store release.xcconfig"; sourceTree = "<group>"; };
1C93CF3971B64E8B6C1F9AC1 /* Pods-SignalShareExtension.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalShareExtension.test.xcconfig"; path = "Pods/Target Support Files/Pods-SignalShareExtension/Pods-SignalShareExtension.test.xcconfig"; sourceTree = "<group>"; };
1CE3CD5C23334683BDD3D78C /* Pods-Signal.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Signal.test.xcconfig"; path = "Pods/Target Support Files/Pods-Signal/Pods-Signal.test.xcconfig"; sourceTree = "<group>"; };
2400888D239F30A600305217 /* SessionRestorationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionRestorationView.swift; sourceTree = "<group>"; };
@ -1344,6 +1359,11 @@
76C87F18181EFCE600C4ACAB /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; };
76EB03C218170B33006006FC /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
76EB03C318170B33006006FC /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
7BC01A3B241F40AB00BC7C55 /* LokiPushNotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = LokiPushNotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; };
7BC01A3D241F40AB00BC7C55 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
7BC01A3F241F40AB00BC7C55 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
7BDCFC0424206E7300641C39 /* LokiPushNotificationService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = LokiPushNotificationService.entitlements; sourceTree = "<group>"; };
7BDCFC07242186E700641C39 /* NotificationServiceExtensionContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationServiceExtensionContext.swift; sourceTree = "<group>"; };
8981C8F64D94D3C52EB67A2C /* Pods-SignalTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-SignalTests/Pods-SignalTests.test.xcconfig"; sourceTree = "<group>"; };
8EEE74B0753448C085B48721 /* Pods-SignalMessaging.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalMessaging.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SignalMessaging/Pods-SignalMessaging.app store release.xcconfig"; sourceTree = "<group>"; };
948239851C08032C842937CC /* Pods-SignalMessaging.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalMessaging.test.xcconfig"; path = "Pods/Target Support Files/Pods-SignalMessaging/Pods-SignalMessaging.test.xcconfig"; sourceTree = "<group>"; };
@ -1427,7 +1447,6 @@
B846365A22B7418B00AF1514 /* Identicon+ObjC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Identicon+ObjC.swift"; sourceTree = "<group>"; };
B84664F4235022F30083A1CD /* MentionUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionUtilities.swift; sourceTree = "<group>"; };
B847570023D568EB00759540 /* SignalServiceKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SignalServiceKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
B847570223D5698100759540 /* LokiPushNotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LokiPushNotificationManager.swift; sourceTree = "<group>"; };
B85357BE23A1AE0800AAF6CD /* SeedReminderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedReminderView.swift; sourceTree = "<group>"; };
B85357C023A1B81900AAF6CD /* SeedReminderViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedReminderViewDelegate.swift; sourceTree = "<group>"; };
B85357C223A1BD1200AAF6CD /* SeedVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedVC.swift; sourceTree = "<group>"; };
@ -1496,6 +1515,7 @@
E85DB184824BA9DC302EC8B3 /* Pods-SignalTests.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalTests.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SignalTests/Pods-SignalTests.app store release.xcconfig"; sourceTree = "<group>"; };
EF764C331DB67CC5000D9A87 /* UIViewController+Permissions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIViewController+Permissions.h"; path = "util/UIViewController+Permissions.h"; sourceTree = "<group>"; };
EF764C341DB67CC5000D9A87 /* UIViewController+Permissions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIViewController+Permissions.m"; path = "util/UIViewController+Permissions.m"; sourceTree = "<group>"; };
F62ECF7B8AF4F8089AA705B3 /* Pods-LokiPushNotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LokiPushNotificationService.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LokiPushNotificationService/Pods-LokiPushNotificationService.debug.xcconfig"; sourceTree = "<group>"; };
FC3BD9871A30A790005B96BB /* Social.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Social.framework; path = System/Library/Frameworks/Social.framework; sourceTree = SDKROOT; };
FC5CDF371A3393DD00B47253 /* error_white@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "error_white@2x.png"; sourceTree = "<group>"; };
FC5CDF381A3393DD00B47253 /* warning_white@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "warning_white@2x.png"; sourceTree = "<group>"; };
@ -1521,6 +1541,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
7BC01A38241F40AB00BC7C55 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
390650A6D345BFE01E006DB0 /* Pods_LokiPushNotificationService.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D221A086169C9E5E00537ABF /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@ -2600,6 +2628,17 @@
path = views;
sourceTree = "<group>";
};
7BC01A3C241F40AB00BC7C55 /* LokiPushNotificationService */ = {
isa = PBXGroup;
children = (
7BDCFC07242186E700641C39 /* NotificationServiceExtensionContext.swift */,
7BDCFC0424206E7300641C39 /* LokiPushNotificationService.entitlements */,
7BC01A3D241F40AB00BC7C55 /* NotificationService.swift */,
7BC01A3F241F40AB00BC7C55 /* Info.plist */,
);
path = LokiPushNotificationService;
sourceTree = "<group>";
};
9404664EC513585B05DF1350 /* Pods */ = {
isa = PBXGroup;
children = (
@ -2615,6 +2654,8 @@
9B533A9FA46206D3D99C9ADA /* Pods-SignalMessaging.debug.xcconfig */,
948239851C08032C842937CC /* Pods-SignalMessaging.test.xcconfig */,
8EEE74B0753448C085B48721 /* Pods-SignalMessaging.app store release.xcconfig */,
F62ECF7B8AF4F8089AA705B3 /* Pods-LokiPushNotificationService.debug.xcconfig */,
18D19142FD6E60FD0A5D89F7 /* Pods-LokiPushNotificationService.app store release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
@ -2838,7 +2879,6 @@
isa = PBXGroup;
children = (
B8544E3223D50E4900299F14 /* AppearanceUtilities.swift */,
B847570223D5698100759540 /* LokiPushNotificationManager.swift */,
B84664F4235022F30083A1CD /* MentionUtilities.swift */,
B886B4A82398BA1500211ABE /* QRCode.swift */,
B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */,
@ -2886,6 +2926,7 @@
D221A093169C9E5E00537ABF /* Signal */,
453518691FC635DD00210559 /* SignalShareExtension */,
453518931FC63DBF00210559 /* SignalMessaging */,
7BC01A3C241F40AB00BC7C55 /* LokiPushNotificationService */,
D221A08C169C9E5E00537ABF /* Frameworks */,
D221A08A169C9E5E00537ABF /* Products */,
9404664EC513585B05DF1350 /* Pods */,
@ -2899,6 +2940,7 @@
D221A0AA169C9E5F00537ABF /* SignalTests.xctest */,
453518681FC635DD00210559 /* SignalShareExtension.appex */,
453518921FC63DBF00210559 /* SignalMessaging.framework */,
7BC01A3B241F40AB00BC7C55 /* LokiPushNotificationService.appex */,
);
name = Products;
sourceTree = "<group>";
@ -2944,6 +2986,7 @@
0F94C85CB0B235DA37F68ED0 /* Pods_SignalShareExtension.framework */,
748A5CAEDD7C919FC64C6807 /* Pods_SignalTests.framework */,
264242150E87D10A357DB07B /* Pods_SignalMessaging.framework */,
04912E453971FB16E5E78EC6 /* Pods_LokiPushNotificationService.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@ -3112,6 +3155,24 @@
productReference = 453518921FC63DBF00210559 /* SignalMessaging.framework */;
productType = "com.apple.product-type.framework";
};
7BC01A3A241F40AB00BC7C55 /* LokiPushNotificationService */ = {
isa = PBXNativeTarget;
buildConfigurationList = 7BC01A45241F40AB00BC7C55 /* Build configuration list for PBXNativeTarget "LokiPushNotificationService" */;
buildPhases = (
4B4609DACEC6E462A2394D2F /* [CP] Check Pods Manifest.lock */,
7BC01A37241F40AB00BC7C55 /* Sources */,
7BC01A38241F40AB00BC7C55 /* Frameworks */,
7BC01A39241F40AB00BC7C55 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = LokiPushNotificationService;
productName = LokiPushNotificationService;
productReference = 7BC01A3B241F40AB00BC7C55 /* LokiPushNotificationService.appex */;
productType = "com.apple.product-type.app-extension";
};
D221A088169C9E5E00537ABF /* Signal */ = {
isa = PBXNativeTarget;
buildConfigurationList = D221A0BC169C9E5F00537ABF /* Build configuration list for PBXNativeTarget "Signal" */;
@ -3133,6 +3194,7 @@
dependencies = (
453518711FC635DD00210559 /* PBXTargetDependency */,
453518981FC63DBF00210559 /* PBXTargetDependency */,
7BC01A41241F40AB00BC7C55 /* PBXTargetDependency */,
);
name = Signal;
productName = RedPhone;
@ -3167,7 +3229,8 @@
D221A080169C9E5E00537ABF /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
DefaultBuildSystemTypeForWorkspace = Original;
LastSwiftUpdateCheck = 1130;
LastTestingUpgradeCheck = 0600;
LastUpgradeCheck = 1020;
ORGANIZATIONNAME = "Open Whisper Systems";
@ -3198,6 +3261,11 @@
LastSwiftMigration = 1020;
ProvisioningStyle = Automatic;
};
7BC01A3A241F40AB00BC7C55 = {
CreatedOnToolsVersion = 11.3.1;
DevelopmentTeam = SUQ8J2PCT7;
ProvisioningStyle = Automatic;
};
D221A088169C9E5E00537ABF = {
DevelopmentTeam = SUQ8J2PCT7;
LastSwiftMigration = 1020;
@ -3310,6 +3378,7 @@
D221A0A9169C9E5F00537ABF /* SignalTests */,
453518671FC635DD00210559 /* SignalShareExtension */,
453518911FC63DBF00210559 /* SignalMessaging */,
7BC01A3A241F40AB00BC7C55 /* LokiPushNotificationService */,
);
};
/* End PBXProject section */
@ -3337,6 +3406,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
7BC01A39241F40AB00BC7C55 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
7BDCFC0B2421EB7600641C39 /* Localizable.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D221A087169C9E5E00537ABF /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@ -3525,13 +3602,35 @@
shellPath = /bin/sh;
shellScript = "if which swiftlint >/dev/null; then\n# disabled for now. too many lint errors outside of the scope of this branch\n#(cd Signal && swiftlint)\n# never fail.\nexit 0\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
};
4B4609DACEC6E462A2394D2F /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-LokiPushNotificationService-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
59C9DBA462715B5C999FFB02 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-Signal/Pods-Signal-frameworks.sh",
"${PODS_ROOT}/Target Support Files/Pods-Signal/Pods-Signal-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/AFNetworking/AFNetworking.framework",
"${BUILT_PRODUCTS_DIR}/AxolotlKit/AxolotlKit.framework",
"${BUILT_PRODUCTS_DIR}/CocoaLumberjack/CocoaLumberjack.framework",
@ -3543,7 +3642,6 @@
"${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework",
"${BUILT_PRODUCTS_DIR}/HKDFKit/HKDFKit.framework",
"${BUILT_PRODUCTS_DIR}/Mantle/Mantle.framework",
"${BUILT_PRODUCTS_DIR}/Mixpanel/Mixpanel.framework",
"${BUILT_PRODUCTS_DIR}/NVActivityIndicatorView/NVActivityIndicatorView.framework",
"${BUILT_PRODUCTS_DIR}/PromiseKit/PromiseKit.framework",
"${BUILT_PRODUCTS_DIR}/PureLayout/PureLayout.framework",
@ -3573,7 +3671,6 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/HKDFKit.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Mantle.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Mixpanel.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/NVActivityIndicatorView.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PromiseKit.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PureLayout.framework",
@ -3592,7 +3689,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Signal/Pods-Signal-frameworks.sh\"\n";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Signal/Pods-Signal-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
6565655F4068F9E5CDC5687F /* [CP] Check Pods Manifest.lock */ = {
@ -3619,7 +3716,7 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-SignalTests/Pods-SignalTests-frameworks.sh",
"${PODS_ROOT}/Target Support Files/Pods-SignalTests/Pods-SignalTests-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/AFNetworking/AFNetworking.framework",
"${BUILT_PRODUCTS_DIR}/AxolotlKit/AxolotlKit.framework",
"${BUILT_PRODUCTS_DIR}/CocoaLumberjack/CocoaLumberjack.framework",
@ -3668,7 +3765,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SignalTests/Pods-SignalTests-frameworks.sh\"\n";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SignalTests/Pods-SignalTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
C3B782012411C26000C859D8 /* Set up Crashlytics */ = {
@ -3886,6 +3983,16 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
7BC01A37241F40AB00BC7C55 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
7BDCFC08242186E700641C39 /* NotificationServiceExtensionContext.swift in Sources */,
7BC01A3E241F40AB00BC7C55 /* NotificationService.swift in Sources */,
7BDCFC092421894900641C39 /* MessageFetcherJob.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D221A085169C9E5E00537ABF /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@ -3923,7 +4030,6 @@
34D99CE4217509C2000AFB39 /* AppEnvironment.swift in Sources */,
348570A820F67575004FF32B /* OWSMessageHeaderView.m in Sources */,
450DF2091E0DD2C6003D14BE /* UserNotificationsAdaptee.swift in Sources */,
B847570323D5698100759540 /* LokiPushNotificationManager.swift in Sources */,
34B6A907218B5241007C4606 /* TypingIndicatorCell.swift in Sources */,
4CFD151D22415AA400F2450F /* CallVideoHintView.swift in Sources */,
34D1F0AB1F867BFC0066283D /* OWSContactOffersCell.m in Sources */,
@ -4203,6 +4309,11 @@
target = 453518911FC63DBF00210559 /* SignalMessaging */;
targetProxy = 453518971FC63DBF00210559 /* PBXContainerItemProxy */;
};
7BC01A41241F40AB00BC7C55 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 7BC01A3A241F40AB00BC7C55 /* LokiPushNotificationService */;
targetProxy = 7BC01A40241F40AB00BC7C55 /* PBXContainerItemProxy */;
};
B6AFCEBB19A93DA60098CFCB /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D221A088169C9E5E00537ABF /* Signal */;
@ -4519,6 +4630,121 @@
};
name = "App Store Release";
};
7BC01A43241F40AB00BC7C55 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = F62ECF7B8AF4F8089AA705B3 /* Pods-LokiPushNotificationService.debug.xcconfig */;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = LokiPushNotificationService/LokiPushNotificationService.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 65;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = SUQ8J2PCT7;
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
INFOPLIST_FILE = LokiPushNotificationService/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MARKETING_VERSION = 1.0.8;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.push-notification-service";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
7BC01A44241F40AB00BC7C55 /* App Store Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 18D19142FD6E60FD0A5D89F7 /* Pods-LokiPushNotificationService.app store release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_ENTITLEMENTS = LokiPushNotificationService/LokiPushNotificationService.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 65;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = SUQ8J2PCT7;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = LokiPushNotificationService/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MARKETING_VERSION = 1.0.8;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.push-notification-service";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = "App Store Release";
};
D221A0BA169C9E5F00537ABF /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@ -4591,6 +4817,7 @@
"-fobjc-arc-exceptions",
"-Werror=protocol",
);
"OTHER_SWIFT_FLAGS[arch=*]" = "-D DEBUG";
SDKROOT = iphoneos;
SWIFT_VERSION = 4.0;
VALIDATE_PRODUCT = YES;
@ -4945,6 +5172,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = "App Store Release";
};
7BC01A45241F40AB00BC7C55 /* Build configuration list for PBXNativeTarget "LokiPushNotificationService" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7BC01A43241F40AB00BC7C55 /* Debug */,
7BC01A44241F40AB00BC7C55 /* App Store Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = "App Store Release";
};
D221A083169C9E5E00537ABF /* Build configuration list for PBXProject "Signal" */ = {
isa = XCConfigurationList;
buildConfigurations = (

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1140"
wasCreatedForAppExtension = "YES"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7BC01A3A241F40AB00BC7C55"
BuildableName = "LokiPushNotificationService.appex"
BlueprintName = "LokiPushNotificationService"
ReferencedContainer = "container:Signal.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D221A088169C9E5E00537ABF"
BuildableName = "Session.app"
BlueprintName = "Signal"
ReferencedContainer = "container:Signal.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D221A088169C9E5E00537ABF"
BuildableName = "Session.app"
BlueprintName = "Signal"
ReferencedContainer = "container:Signal.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "App Store Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D221A088169C9E5E00537ABF"
BuildableName = "Session.app"
BlueprintName = "Signal"
ReferencedContainer = "container:Signal.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "App Store Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

@ -28,7 +28,7 @@
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A16588799C7A0AB3A5ACEF8339CCB8BC"
BlueprintIdentifier = "56FEAC3FCA8ADA9B6D3602FBA38B2527"
BuildableName = "SignalServiceKit.framework"
BlueprintName = "SignalServiceKit"
ReferencedContainer = "container:Pods/Pods.xcodeproj">
@ -72,7 +72,7 @@
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "24F8DED46F845407BED93AD1BC0D4E85"
BlueprintIdentifier = "3FC719A0D2B2FA321E696D83720CAC6F"
BuildableName = "SignalServiceKit-Unit-Tests.xctest"
BlueprintName = "SignalServiceKit-Unit-Tests"
ReferencedContainer = "container:Pods/Pods.xcodeproj">
@ -180,7 +180,7 @@
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "3966AB1BF4A267B3775E55BB346C42BB"
BlueprintIdentifier = "3AC929F2E4978F42ED9E9EA232D7247B"
BuildableName = "SignalCoreKit-Unit-Tests.xctest"
BlueprintName = "SignalCoreKit-Unit-Tests"
ReferencedContainer = "container:Pods/Pods.xcodeproj">
@ -190,7 +190,7 @@
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "FBEFD7D60C586B4EBC4A2D8A609B1884"
BlueprintIdentifier = "5B34FB0B5ABA685EF33F1BA1C388F016"
BuildableName = "AxolotlKit-Unit-Tests.xctest"
BlueprintName = "AxolotlKit-Unit-Tests"
ReferencedContainer = "container:Pods/Pods.xcodeproj">
@ -200,7 +200,7 @@
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "217139450FBCFCCE72F03EFEE0C5DA38"
BlueprintIdentifier = "D85B45003BA81D72F606FDF3EB4B4E1C"
BuildableName = "Curve25519Kit-Unit-Tests.xctest"
BlueprintName = "Curve25519Kit-Unit-Tests"
ReferencedContainer = "container:Pods/Pods.xcodeproj">
@ -210,7 +210,7 @@
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CB39B3A5A9E8A82A835D8CD5DEBB7CDC"
BlueprintIdentifier = "F9C2DA0BADF4F69559F0AA5BB4FC1E06"
BuildableName = "HKDFKit-Unit-Tests.xctest"
BlueprintName = "HKDFKit-Unit-Tests"
ReferencedContainer = "container:Pods/Pods.xcodeproj">
@ -220,7 +220,7 @@
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B620B404CB76E484E77870B9AD32320E"
BlueprintIdentifier = "92057C418B970541FF6BE6E64A49D8C2"
BuildableName = "SignalMetadataKit-Unit-Tests.xctest"
BlueprintName = "SignalMetadataKit-Unit-Tests"
ReferencedContainer = "container:Pods/Pods.xcodeproj">

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1140"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "453518911FC63DBF00210559"
BuildableName = "SignalMessaging.framework"
BlueprintName = "SignalMessaging"
ReferencedContainer = "container:Signal.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "App Store Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "453518911FC63DBF00210559"
BuildableName = "SignalMessaging.framework"
BlueprintName = "SignalMessaging"
ReferencedContainer = "container:Signal.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "App Store Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

@ -4,5 +4,7 @@
<dict>
<key>BuildSystemType</key>
<string>Original</string>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

@ -113,7 +113,7 @@
<key>NSContactsUsageDescription</key>
<string>Signal uses your contacts to find users you know. We do not store your contacts on the server.</string>
<key>NSFaceIDUsageDescription</key>
<string>Session&apos;s Screen Lock feature uses Face ID.</string>
<string>Session's Screen Lock feature uses Face ID.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Session needs access to your microphone to record videos.</string>
<key>NSPhotoLibraryAddUsageDescription</key>

@ -269,6 +269,10 @@ public final class LokiAPI : NSObject {
private static func updateLastMessageHashValueIfPossible(for target: LokiAPITarget, from rawMessages: [JSON]) {
if let lastMessage = rawMessages.last, let hashValue = lastMessage["hash"] as? String, let expirationDate = lastMessage["expiration"] as? Int {
setLastMessageHashValue(for: target, hashValue: hashValue, expirationDate: UInt64(expirationDate))
// FIXME: Move this out of here
if UserDefaults.standard[.isUsingFullAPNs] {
LokiPushNotificationManager.acknowledgeDelivery(forMessageWithHash: hashValue, expiration: expirationDate, hexEncodedPublicKey: userHexEncodedPublicKey)
}
} else if (!rawMessages.isEmpty) {
print("[Loki] Failed to update last message hash value from: \(rawMessages).")
}

@ -1,160 +1,160 @@
// Loki: Refer to Docs/SessionReset.md for explanations
#import "SessionCipher+Loki.h"
#import "NSNotificationCenter+OWS.h"
#import "PreKeyWhisperMessage.h"
#import "OWSPrimaryStorage+Loki.h"
#import "TSContactThread.h"
#import <YapDatabase/YapDatabase.h>
NSString *const kNSNotificationName_SessionAdopted = @"kNSNotificationName_SessionAdopted";
NSString *const kNSNotificationKey_ContactPubKey = @"kNSNotificationKey_ContactPubKey";
@interface SessionCipher ()
@property (nonatomic, readonly) NSString *recipientId;
@property (nonatomic, readonly) int deviceId;
@property (nonatomic, readonly) id<SessionStore> sessionStore;
@property (nonatomic, readonly) id<PreKeyStore> prekeyStore;
@end
@implementation SessionCipher (Loki)
- (NSData *)throws_lokiDecrypt:(id<CipherMessage>)whisperMessage protocolContext:(nullable id)protocolContext
{
// Our state before we decrypt the message
SessionState *_Nullable state = [self getCurrentState:protocolContext];
// Verify incoming friend request messages
if (!state) {
[self throws_validatePreKeysForFriendRequestAcceptance:whisperMessage protocolContext:protocolContext];
}
// While decrypting our state may change internally
NSData *plainText = [self throws_decrypt:whisperMessage protocolContext:protocolContext];
// Loki: Handle any session resets
[self handleSessionReset:whisperMessage previousState:state protocolContext:protocolContext];
return plainText;
}
/// Get the current session state
- (SessionState *_Nullable)getCurrentState:(nullable id)protocolContext {
SessionRecord *record = [self.sessionStore loadSession:self.recipientId deviceId:self.deviceId protocolContext:protocolContext];
SessionState *state = record.sessionState;
// Check if session is initialized
if (!state.hasSenderChain) { return nil; }
return state;
}
/// Handle any Loki session reset stuff
- (void)handleSessionReset:(id<CipherMessage>)whisperMessage previousState:(SessionState *_Nullable)previousState protocolContext:(nullable id)protocolContext
{
// Don't bother doing anything if we didn't have a session before
if (!previousState) { return; }
OWSAssertDebug([protocolContext isKindOfClass:[YapDatabaseReadWriteTransaction class]]);
YapDatabaseReadWriteTransaction *transaction = protocolContext;
// Get the thread
TSContactThread *thread = [TSContactThread getThreadWithContactId:self.recipientId transaction:transaction];
if (!thread) { return; }
// Bail early if no session reset is in progress
if (thread.sessionResetState == TSContactThreadSessionResetStateNone) { return; }
BOOL sessionResetReceived = thread.sessionResetState == TSContactThreadSessionResetStateRequestReceived;
SessionState *_Nullable currentState = [self getCurrentState:protocolContext];
// Check if our previous state and our current state differ
if (!currentState || ![currentState.aliceBaseKey isEqualToData:previousState.aliceBaseKey]) {
if (sessionResetReceived) {
// The other user used an old session to contact us.
// Wait for them to use a new one
[self restoreSession:previousState protocolContext:protocolContext];
} else {
// Our session reset went through successfully
// We had initiated a session reset and got a different session back from the user
[self deleteAllSessionsExcept:currentState protocolContext:protocolContext];
[self notifySessionAdopted];
}
} else if (sessionResetReceived) {
// Our session reset went through successfully
// We got a message with the same session from the other user
[self deleteAllSessionsExcept:previousState protocolContext:protocolContext];
[self notifySessionAdopted];
}
}
/// Send a notification about a new session being adopted
- (void)notifySessionAdopted
{
NSDictionary *userInfo = @{ kNSNotificationKey_ContactPubKey : self.recipientId };
[NSNotificationCenter.defaultCenter postNotificationNameAsync:kNSNotificationName_SessionAdopted object:nil userInfo:userInfo];
}
/// Delete all other sessions except the given one
- (void)deleteAllSessionsExcept:(SessionState *)state protocolContext:(nullable id)protocolContext
{
SessionRecord *record = [self.sessionStore loadSession:self.recipientId deviceId:self.deviceId protocolContext:protocolContext];
[record removePreviousSessionStates];
SessionState *newState = state == nil ? [SessionState new] : state;
[record setState:newState];
[self.sessionStore storeSession:self.recipientId deviceId:self.deviceId session:record protocolContext:protocolContext];
}
/// Set the given session as the active one while archiving the old one
- (void)restoreSession:(SessionState *)state protocolContext:(nullable id)protocolContext
{
SessionRecord *record = [self.sessionStore loadSession:self.recipientId deviceId:self.deviceId protocolContext:protocolContext];
// Remove the state from previous session states
[record.previousSessionStates enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(SessionState *obj, NSUInteger idx, BOOL *stop) {
if ([state.aliceBaseKey isEqualToData:obj.aliceBaseKey]) {
[record.previousSessionStates removeObjectAtIndex:idx];
*stop = YES;
}
}];
// Promote it so the previous state gets archived
[record promoteState:state];
[self.sessionStore storeSession:self.recipientId deviceId:self.deviceId session:record protocolContext:protocolContext];
}
/// Check that we have matching pre keys in the case of a `PreKeyWhisperMessage`.
/// This is so that we don't trigger a false friend request accept on unknown contacts.
- (void)throws_validatePreKeysForFriendRequestAcceptance:(id<CipherMessage>)whisperMessage protocolContext:(nullable id)protocolContext {
OWSAssertDebug([protocolContext isKindOfClass:[YapDatabaseReadTransaction class]]);
YapDatabaseReadTransaction *transaction = protocolContext;
// Ignore anything that isn't a `PreKeyWhisperMessage`
if (![whisperMessage isKindOfClass:[PreKeyWhisperMessage class]]) { return; }
// Check the pre key store
if (![self.prekeyStore isKindOfClass:[OWSPrimaryStorage class]]) { return; }
PreKeyWhisperMessage *preKeyMessage = whisperMessage;
OWSPrimaryStorage *primaryStorage = self.prekeyStore;
PreKeyRecord *_Nullable storedPreKey = [primaryStorage getPreKeyForContact:self.recipientId transaction:transaction];
if (!storedPreKey) {
OWSRaiseException(@"Loki", @"Received a friend request from a public key for which no pre key bundle was created.");
}
if (storedPreKey.Id != preKeyMessage.prekeyID) {
OWSRaiseException(@"Loki", @"Received a PreKeyWhisperMessage (friend request accept) from an unknown source.");
}
}
@end
//// Loki: Refer to Docs/SessionReset.md for explanations
//
//#import "SessionCipher+Loki.h"
//#import "NSNotificationCenter+OWS.h"
//#import "PreKeyWhisperMessage.h"
//#import "OWSPrimaryStorage+Loki.h"
//#import "TSContactThread.h"
//#import <YapDatabase/YapDatabase.h>
//
//NSString *const kNSNotificationName_SessionAdopted = @"kNSNotificationName_SessionAdopted";
//NSString *const kNSNotificationKey_ContactPubKey = @"kNSNotificationKey_ContactPubKey";
//
//@interface SessionCipher ()
//
//@property (nonatomic, readonly) NSString *recipientId;
//@property (nonatomic, readonly) int deviceId;
//
//@property (nonatomic, readonly) id<SessionStore> sessionStore;
//@property (nonatomic, readonly) id<PreKeyStore> prekeyStore;
//
//@end
//
//@implementation SessionCipher (Loki)
//
//- (NSData *)throws_lokiDecrypt:(id<CipherMessage>)whisperMessage protocolContext:(nullable id)protocolContext
//{
// // Our state before we decrypt the message
// SessionState *_Nullable state = [self getCurrentState:protocolContext];
//
// // Verify incoming friend request messages
// if (!state) {
// [self throws_validatePreKeysForFriendRequestAcceptance:whisperMessage protocolContext:protocolContext];
// }
//
// // While decrypting our state may change internally
// NSData *plainText = [self throws_decrypt:whisperMessage protocolContext:protocolContext];
//
//
// // Loki: Handle any session resets
// [self handleSessionReset:whisperMessage previousState:state protocolContext:protocolContext];
//
// return plainText;
//}
//
///// Get the current session state
//- (SessionState *_Nullable)getCurrentState:(nullable id)protocolContext {
// SessionRecord *record = [self.sessionStore loadSession:self.recipientId deviceId:self.deviceId protocolContext:protocolContext];
// SessionState *state = record.sessionState;
//
// // Check if session is initialized
// if (!state.hasSenderChain) { return nil; }
//
// return state;
//}
//
///// Handle any Loki session reset stuff
//- (void)handleSessionReset:(id<CipherMessage>)whisperMessage previousState:(SessionState *_Nullable)previousState protocolContext:(nullable id)protocolContext
//{
// // Don't bother doing anything if we didn't have a session before
// if (!previousState) { return; }
//
// OWSAssertDebug([protocolContext isKindOfClass:[YapDatabaseReadWriteTransaction class]]);
// YapDatabaseReadWriteTransaction *transaction = protocolContext;
//
// // Get the thread
// TSContactThread *thread = [TSContactThread getThreadWithContactId:self.recipientId transaction:transaction];
// if (!thread) { return; }
//
// // Bail early if no session reset is in progress
// if (thread.sessionResetState == TSContactThreadSessionResetStateNone) { return; }
//
// BOOL sessionResetReceived = thread.sessionResetState == TSContactThreadSessionResetStateRequestReceived;
// SessionState *_Nullable currentState = [self getCurrentState:protocolContext];
//
// // Check if our previous state and our current state differ
// if (!currentState || ![currentState.aliceBaseKey isEqualToData:previousState.aliceBaseKey]) {
//
// if (sessionResetReceived) {
// // The other user used an old session to contact us.
// // Wait for them to use a new one
// [self restoreSession:previousState protocolContext:protocolContext];
// } else {
// // Our session reset went through successfully
// // We had initiated a session reset and got a different session back from the user
// [self deleteAllSessionsExcept:currentState protocolContext:protocolContext];
// [self notifySessionAdopted];
// }
//
// } else if (sessionResetReceived) {
// // Our session reset went through successfully
// // We got a message with the same session from the other user
// [self deleteAllSessionsExcept:previousState protocolContext:protocolContext];
// [self notifySessionAdopted];
// }
//}
//
///// Send a notification about a new session being adopted
//- (void)notifySessionAdopted
//{
// NSDictionary *userInfo = @{ kNSNotificationKey_ContactPubKey : self.recipientId };
// [NSNotificationCenter.defaultCenter postNotificationNameAsync:kNSNotificationName_SessionAdopted object:nil userInfo:userInfo];
//}
//
///// Delete all other sessions except the given one
//- (void)deleteAllSessionsExcept:(SessionState *)state protocolContext:(nullable id)protocolContext
//{
// SessionRecord *record = [self.sessionStore loadSession:self.recipientId deviceId:self.deviceId protocolContext:protocolContext];
// [record removePreviousSessionStates];
//
// SessionState *newState = state == nil ? [SessionState new] : state;
// [record setState:newState];
//
// [self.sessionStore storeSession:self.recipientId deviceId:self.deviceId session:record protocolContext:protocolContext];
//}
//
///// Set the given session as the active one while archiving the old one
//- (void)restoreSession:(SessionState *)state protocolContext:(nullable id)protocolContext
//{
// SessionRecord *record = [self.sessionStore loadSession:self.recipientId deviceId:self.deviceId protocolContext:protocolContext];
//
// // Remove the state from previous session states
// [record.previousSessionStates enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(SessionState *obj, NSUInteger idx, BOOL *stop) {
// if ([state.aliceBaseKey isEqualToData:obj.aliceBaseKey]) {
// [record.previousSessionStates removeObjectAtIndex:idx];
// *stop = YES;
// }
// }];
//
// // Promote it so the previous state gets archived
// [record promoteState:state];
//
// [self.sessionStore storeSession:self.recipientId deviceId:self.deviceId session:record protocolContext:protocolContext];
//}
//
///// Check that we have matching pre keys in the case of a `PreKeyWhisperMessage`.
///// This is so that we don't trigger a false friend request accept on unknown contacts.
//- (void)throws_validatePreKeysForFriendRequestAcceptance:(id<CipherMessage>)whisperMessage protocolContext:(nullable id)protocolContext {
// OWSAssertDebug([protocolContext isKindOfClass:[YapDatabaseReadTransaction class]]);
// YapDatabaseReadTransaction *transaction = protocolContext;
//
// // Ignore anything that isn't a `PreKeyWhisperMessage`
// if (![whisperMessage isKindOfClass:[PreKeyWhisperMessage class]]) { return; }
//
// // Check the pre key store
// if (![self.prekeyStore isKindOfClass:[OWSPrimaryStorage class]]) { return; }
//
// PreKeyWhisperMessage *preKeyMessage = whisperMessage;
// OWSPrimaryStorage *primaryStorage = self.prekeyStore;
//
// PreKeyRecord *_Nullable storedPreKey = [primaryStorage getPreKeyForContact:self.recipientId transaction:transaction];
// if (!storedPreKey) {
// OWSRaiseException(@"Loki", @"Received a friend request from a public key for which no pre key bundle was created.");
// }
//
// if (storedPreKey.Id != preKeyMessage.prekeyID) {
// OWSRaiseException(@"Loki", @"Received a PreKeyWhisperMessage (friend request accept) from an unknown source.");
// }
//}
//
//@end

@ -13,5 +13,6 @@
#pragma mark Settings
- (BOOL)shouldSyncTranscript { return NO; }
- (BOOL)shouldBeSaved { return NO; }
- (uint)ttl { return 23 * kHourInMs; }
@end

@ -11,6 +11,7 @@
}
- (BOOL)shouldBeSaved { return NO; }
- (uint)ttl { return 23 * kHourInMs; }
#pragma mark Building
- (nullable SSKProtoDataMessageBuilder *)dataMessageBuilder

@ -1,14 +1,12 @@
// Ideally this should be in SignalServiceKit, but somehow linking fails when it is.
@objc(LKPushNotificationManager)
final class LokiPushNotificationManager : NSObject {
// MARK: Settings
#if DEBUG
private static let url = URL(string: "https://dev.apns.getsession.org/register")!
private static let server = "https://dev.apns.getsession.org/"
#else
private static let url = URL(string: "https://live.apns.getsession.org/register")!
private static let server = "https://live.apns.getsession.org/"
#endif
private static let tokenExpirationInterval: TimeInterval = 2 * 24 * 60 * 60
@ -16,6 +14,8 @@ final class LokiPushNotificationManager : NSObject {
private override init() { }
// MARK: Registration
/// Registers the user for silent push notifications (that then trigger the app
/// into fetching messages). Only the user's device token is needed for this.
@objc(registerWithToken:)
static func register(with token: Data) {
let hexEncodedToken = token.toHexString()
@ -31,6 +31,7 @@ final class LokiPushNotificationManager : NSObject {
return print("[Loki] Using full APNs; ignoring call to register(with:).")
}
let parameters = [ "token" : hexEncodedToken ]
let url = URL(string: server + "register")!
let request = TSRequest(url: url, method: "POST", parameters: parameters)
request.allHTTPHeaderFields = [ "Content-Type" : "application/json" ]
TSNetworkManager.shared().makeRequest(request, success: { _, response in
@ -47,13 +48,16 @@ final class LokiPushNotificationManager : NSObject {
print("[Loki] Couldn't register device token.")
})
}
/// Registers the user for normal push notifications. Requires the user's device
/// token and their Session ID.
@objc(registerWithToken:hexEncodedPublicKey:)
static func register(with token: Data, hexEncodedPublicKey: String) {
let hexEncodedToken = token.toHexString()
let userDefaults = UserDefaults.standard
let now = Date().timeIntervalSince1970
let parameters = [ "token" : hexEncodedToken, "pubKey" : hexEncodedPublicKey]
let url = URL(string: server + "register")!
let request = TSRequest(url: url, method: "POST", parameters: parameters)
request.allHTTPHeaderFields = [ "Content-Type" : "application/json" ]
TSNetworkManager.shared().makeRequest(request, success: { _, response in
@ -70,4 +74,22 @@ final class LokiPushNotificationManager : NSObject {
print("[Loki] Couldn't register device token.")
})
}
@objc(acknowledgeDeliveryForMessageWithHash:expiration:hexEncodedPublicKey:)
static func acknowledgeDelivery(forMessageWithHash hash: String, expiration: Int, hexEncodedPublicKey: String) {
let parameters: JSON = [ "lastHash" : hash, "pubKey" : hexEncodedPublicKey, "expiration" : expiration]
let url = URL(string: server + "acknowledge_message_delivery")!
let request = TSRequest(url: url, method: "POST", parameters: parameters)
request.allHTTPHeaderFields = [ "Content-Type" : "application/json" ]
TSNetworkManager.shared().makeRequest(request, success: { _, response in
guard let json = response as? JSON else {
return print("[Loki] Couldn't acknowledge delivery for message with hash: \(hash).")
}
guard json["code"] as? Int != 0 else {
return print("[Loki] Couldn't acknowledge delivery for message with hash: \(hash) due to error: \(json["message"] as? String ?? "nil").")
}
}, failure: { _, error in
print("[Loki] Couldn't acknowledge delivery for message with hash: \(hash).")
})
}
}

@ -255,10 +255,6 @@ NS_ASSUME_NONNULL_BEGIN
OWSFailDebug(@"Not registered.");
return;
}
if (!CurrentAppContext().isMainApp) {
OWSFail(@"Not the main app.");
return;
}
OWSLogInfo(@"Handling decrypted envelope: %@.", [self descriptionForEnvelope:envelope]);

@ -99,7 +99,7 @@ public class TypingIndicatorMessage: TSOutgoingMessage {
public override func shouldBeSaved() -> Bool {
return false
}
@objc
public override var ttl: UInt32 { return UInt32(2 * kMinuteInMs) }

@ -88,6 +88,8 @@ NSString *const kSessionStoreDBConnectionKey = @"kSessionStoreDBConnectionKey";
OWSAssertDebug(contactIdentifier.length > 0);
OWSAssertDebug(deviceId >= 0);
OWSAssertDebug([protocolContext isKindOfClass:[YapDatabaseReadWriteTransaction class]]);
// TODO: Needs a comment from Ryan
if (!CurrentAppContext().isMainApp) { return; }
YapDatabaseReadWriteTransaction *transaction = protocolContext;

Loading…
Cancel
Save