Cleaning up final things before release

Added basic support for the '25' blinded prefix
Fixed a unit test CI issue
This commit is contained in:
Morgan Pretty 2023-07-14 14:36:59 +10:00
parent f13f75eedf
commit bc5d8d0931
36 changed files with 263 additions and 127 deletions

View File

@ -146,7 +146,8 @@ extension ContextMenuVC {
for cellViewModel: MessageViewModel,
recentEmojis: [EmojiWithSkinTones],
currentUserPublicKey: String,
currentUserBlindedPublicKey: String?,
currentUserBlinded15PublicKey: String?,
currentUserBlinded25PublicKey: String?,
currentUserIsOpenGroupModerator: Bool,
currentThreadIsMessageRequest: Bool,
delegate: ContextMenuActionDelegate?
@ -204,7 +205,8 @@ extension ContextMenuVC {
cellViewModel.threadVariant != .community ||
currentUserIsOpenGroupModerator ||
cellViewModel.authorId == currentUserPublicKey ||
cellViewModel.authorId == currentUserBlindedPublicKey ||
cellViewModel.authorId == currentUserBlinded15PublicKey ||
cellViewModel.authorId == currentUserBlinded25PublicKey ||
cellViewModel.state == .failed
)
let canBan: Bool = (

View File

@ -739,7 +739,8 @@ extension ConversationVC:
for: cellViewModel,
recentEmojis: (self.viewModel.threadData.recentReactionEmoji ?? []).compactMap { EmojiWithSkinTones(rawValue: $0) },
currentUserPublicKey: self.viewModel.threadData.currentUserPublicKey,
currentUserBlindedPublicKey: self.viewModel.threadData.currentUserBlindedPublicKey,
currentUserBlinded15PublicKey: self.viewModel.threadData.currentUserBlinded15PublicKey,
currentUserBlinded25PublicKey: self.viewModel.threadData.currentUserBlinded25PublicKey,
currentUserIsOpenGroupModerator: OpenGroupManager.isUserModeratorOrAdmin(
self.viewModel.threadData.currentUserPublicKey,
for: self.viewModel.threadData.openGroupRoomToken,
@ -1018,7 +1019,7 @@ extension ConversationVC:
func startThread(with sessionId: String, openGroupServer: String?, openGroupPublicKey: String?) {
guard viewModel.threadData.canWrite else { return }
guard SessionId.Prefix(from: sessionId) == .blinded else {
guard SessionId.Prefix(from: sessionId) == .blinded15 || SessionId.Prefix(from: sessionId) == .blinded25 else {
Storage.shared.write { db in
try SessionThread
.fetchOrCreate(db, id: sessionId, variant: .contact, shouldBeVisible: nil)
@ -1661,7 +1662,8 @@ extension ConversationVC:
attachments: cellViewModel.attachments,
linkPreviewAttachment: cellViewModel.linkPreviewAttachment,
currentUserPublicKey: cellViewModel.currentUserPublicKey,
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey
currentUserBlinded15PublicKey: cellViewModel.currentUserBlinded15PublicKey,
currentUserBlinded25PublicKey: cellViewModel.currentUserBlinded25PublicKey
)
guard let quoteDraft: QuotedReplyModel = maybeQuoteDraft else { return }

View File

@ -638,7 +638,10 @@ final class ConversationVC: BaseVC, SessionUtilRespondingViewController, Convers
// and need to swap over to the new one
guard
let sessionId: String = self?.viewModel.threadData.threadId,
SessionId.Prefix(from: sessionId) == .blinded,
(
SessionId.Prefix(from: sessionId) == .blinded15 ||
SessionId.Prefix(from: sessionId) == .blinded25
),
let blindedLookup: BlindedIdLookup = Storage.shared.read({ db in
try BlindedIdLookup
.filter(id: sessionId)

View File

@ -71,7 +71,8 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
threadIsBlocked: Bool,
currentUserIsClosedGroupMember: Bool?,
openGroupPermissions: OpenGroup.Permissions?,
blindedKey: String?
blinded15Key: String?,
blinded25Key: String?
)
let initialData: InitialData? = Storage.shared.read { db -> InitialData in
@ -110,10 +111,17 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
.asRequest(of: OpenGroup.Permissions.self)
.fetchOne(db)
)
let blindedKey: String? = SessionThread.getUserHexEncodedBlindedKey(
let blinded15Key: String? = SessionThread.getUserHexEncodedBlindedKey(
db,
threadId: threadId,
threadVariant: threadVariant
threadVariant: threadVariant,
blindingPrefix: .blinded15
)
let blinded25Key: String? = SessionThread.getUserHexEncodedBlindedKey(
db,
threadId: threadId,
threadVariant: threadVariant,
blindingPrefix: .blinded25
)
return (
@ -122,7 +130,8 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
threadIsBlocked,
currentUserIsClosedGroupMember,
openGroupPermissions,
blindedKey
blinded15Key,
blinded25Key
)
}
@ -138,7 +147,10 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
threadIsBlocked: initialData?.threadIsBlocked,
currentUserIsClosedGroupMember: initialData?.currentUserIsClosedGroupMember,
openGroupPermissions: initialData?.openGroupPermissions
).populatingCurrentUserBlindedKey(currentUserBlindedPublicKeyForThisThread: initialData?.blindedKey)
).populatingCurrentUserBlindedKeys(
currentUserBlinded15PublicKeyForThisThread: initialData?.blinded15Key,
currentUserBlinded25PublicKeyForThisThread: initialData?.blinded25Key
)
self.pagedDataObserver = nil
// Note: Since this references self we need to finish initializing before setting it, we
@ -148,10 +160,8 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
self.pagedDataObserver = self.setupPagedObserver(
for: threadId,
userPublicKey: (initialData?.currentUserPublicKey ?? getUserHexEncodedPublicKey()),
blindedPublicKey: SessionThread.getUserHexEncodedBlindedKey(
threadId: threadId,
threadVariant: threadVariant
)
blinded15PublicKey: initialData?.blinded15Key,
blinded25PublicKey: initialData?.blinded25Key
)
// Run the initial query on a background thread so we don't block the push transition
@ -197,9 +207,10 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
return threadViewModel
.map { $0.with(recentReactionEmoji: recentReactionEmoji) }
.map { viewModel -> SessionThreadViewModel in
viewModel.populatingCurrentUserBlindedKey(
viewModel.populatingCurrentUserBlindedKeys(
db,
currentUserBlindedPublicKeyForThisThread: self?.threadData.currentUserBlindedPublicKey
currentUserBlinded15PublicKeyForThisThread: self?.threadData.currentUserBlinded15PublicKey,
currentUserBlinded25PublicKeyForThisThread: self?.threadData.currentUserBlinded25PublicKey
)
}
}
@ -237,7 +248,12 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
}
}
private func setupPagedObserver(for threadId: String, userPublicKey: String, blindedPublicKey: String?) -> PagedDatabaseObserver<Interaction, MessageViewModel> {
private func setupPagedObserver(
for threadId: String,
userPublicKey: String,
blinded15PublicKey: String?,
blinded25PublicKey: String?
) -> PagedDatabaseObserver<Interaction, MessageViewModel> {
return PagedDatabaseObserver(
pagedTable: Interaction.self,
pageSize: ConversationViewModel.pageSize,
@ -285,7 +301,8 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
orderSQL: MessageViewModel.orderSQL,
dataQuery: MessageViewModel.baseQuery(
userPublicKey: userPublicKey,
blindedPublicKey: blindedPublicKey,
blinded15PublicKey: blinded15PublicKey,
blinded25PublicKey: blinded25PublicKey,
orderSQL: MessageViewModel.orderSQL,
groupSQL: MessageViewModel.groupSQL
),
@ -391,12 +408,14 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
cellViewModel.id == sortedData
.filter {
$0.authorId == threadData.currentUserPublicKey ||
$0.authorId == threadData.currentUserBlindedPublicKey
$0.authorId == threadData.currentUserBlinded15PublicKey ||
$0.authorId == threadData.currentUserBlinded25PublicKey
}
.last?
.id
),
currentUserBlindedPublicKey: threadData.currentUserBlindedPublicKey
currentUserBlinded15PublicKey: threadData.currentUserBlinded15PublicKey,
currentUserBlinded25PublicKey: threadData.currentUserBlinded25PublicKey
)
}
.reduce([]) { result, message in
@ -460,14 +479,15 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
let currentUserProfile: Profile = Profile.fetchOrCreateCurrentUser()
let interaction: Interaction = Interaction(
threadId: threadData.threadId,
authorId: (threadData.currentUserBlindedPublicKey ?? threadData.currentUserPublicKey),
authorId: (threadData.currentUserBlinded15PublicKey ?? threadData.currentUserPublicKey),
variant: .standardOutgoing,
body: text,
timestampMs: sentTimestampMs,
hasMention: Interaction.isUserMentioned(
publicKeysToCheck: [
threadData.currentUserPublicKey,
threadData.currentUserBlindedPublicKey
threadData.currentUserBlinded15PublicKey,
threadData.currentUserBlinded25PublicKey
].compactMap { $0 },
body: text
),
@ -601,9 +621,9 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
.fetchSet(db)
)
.defaulting(to: [])
let targetPrefix: SessionId.Prefix = (capabilities.contains(.blind) ?
.blinded :
.standard
let targetPrefixes: [SessionId.Prefix] = (capabilities.contains(.blind) ?
[.blinded15, .blinded25] :
[.standard]
)
return (try MentionInfo
@ -611,7 +631,7 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
userPublicKey: userPublicKey,
threadId: threadData.threadId,
threadVariant: threadData.threadVariant,
targetPrefix: targetPrefix,
targetPrefixes: targetPrefixes,
pattern: pattern
)?
.fetchAll(db))
@ -706,7 +726,8 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
self.pagedDataObserver = self.setupPagedObserver(
for: updatedThreadId,
userPublicKey: getUserHexEncodedPublicKey(),
blindedPublicKey: nil
blinded15PublicKey: nil,
blinded25PublicKey: nil
)
// Try load everything up to the initial visible message, fallback to just the initial page of messages

View File

@ -265,7 +265,8 @@ final class InputView: UIView, InputViewButtonDelegate, InputTextViewDelegate, M
quotedText: quoteDraftInfo.model.body,
threadVariant: threadVariant,
currentUserPublicKey: quoteDraftInfo.model.currentUserPublicKey,
currentUserBlindedPublicKey: quoteDraftInfo.model.currentUserBlindedPublicKey,
currentUserBlinded15PublicKey: quoteDraftInfo.model.currentUserBlinded15PublicKey,
currentUserBlinded25PublicKey: quoteDraftInfo.model.currentUserBlinded25PublicKey,
direction: (quoteDraftInfo.isOutgoing ? .outgoing : .incoming),
attachment: quoteDraftInfo.model.attachment,
hInset: hInset,

View File

@ -30,7 +30,8 @@ final class QuoteView: UIView {
quotedText: String?,
threadVariant: SessionThread.Variant,
currentUserPublicKey: String?,
currentUserBlindedPublicKey: String?,
currentUserBlinded15PublicKey: String?,
currentUserBlinded25PublicKey: String?,
direction: Direction,
attachment: Attachment?,
hInset: CGFloat,
@ -47,7 +48,8 @@ final class QuoteView: UIView {
quotedText: quotedText,
threadVariant: threadVariant,
currentUserPublicKey: currentUserPublicKey,
currentUserBlindedPublicKey: currentUserBlindedPublicKey,
currentUserBlinded15PublicKey: currentUserBlinded15PublicKey,
currentUserBlinded25PublicKey: currentUserBlinded25PublicKey,
direction: direction,
attachment: attachment,
hInset: hInset,
@ -69,7 +71,8 @@ final class QuoteView: UIView {
quotedText: String?,
threadVariant: SessionThread.Variant,
currentUserPublicKey: String?,
currentUserBlindedPublicKey: String?,
currentUserBlinded15PublicKey: String?,
currentUserBlinded25PublicKey: String?,
direction: Direction,
attachment: Attachment?,
hInset: CGFloat,
@ -211,7 +214,8 @@ final class QuoteView: UIView {
in: $0,
threadVariant: threadVariant,
currentUserPublicKey: currentUserPublicKey,
currentUserBlindedPublicKey: currentUserBlindedPublicKey,
currentUserBlinded15PublicKey: currentUserBlinded15PublicKey,
currentUserBlinded25PublicKey: currentUserBlinded25PublicKey,
isOutgoingMessage: (direction == .outgoing),
textColor: textColor,
theme: theme,
@ -234,7 +238,8 @@ final class QuoteView: UIView {
let isCurrentUser: Bool = [
currentUserPublicKey,
currentUserBlindedPublicKey,
currentUserBlinded15PublicKey,
currentUserBlinded25PublicKey
]
.compactMap { $0 }
.asSet()

View File

@ -542,7 +542,8 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate {
quotedText: quote.body,
threadVariant: cellViewModel.threadVariant,
currentUserPublicKey: cellViewModel.currentUserPublicKey,
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey,
currentUserBlinded15PublicKey: cellViewModel.currentUserBlinded15PublicKey,
currentUserBlinded25PublicKey: cellViewModel.currentUserBlinded25PublicKey,
direction: (cellViewModel.variant == .standardOutgoing ?
.outgoing :
.incoming
@ -868,7 +869,10 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate {
if profilePictureView.bounds.contains(profilePictureView.convert(location, from: self)), cellViewModel.shouldShowProfile {
// For open groups only attempt to start a conversation if the author has a blinded id
guard cellViewModel.threadVariant != .community else {
guard SessionId.Prefix(from: cellViewModel.authorId) == .blinded else { return }
guard
SessionId.Prefix(from: cellViewModel.authorId) == .blinded15 ||
SessionId.Prefix(from: cellViewModel.authorId) == .blinded25
else { return }
delegate?.startThread(
with: cellViewModel.authorId,
@ -1118,7 +1122,8 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate {
in: (cellViewModel.body ?? ""),
threadVariant: cellViewModel.threadVariant,
currentUserPublicKey: cellViewModel.currentUserPublicKey,
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey,
currentUserBlinded15PublicKey: cellViewModel.currentUserBlinded15PublicKey,
currentUserBlinded25PublicKey: cellViewModel.currentUserBlinded25PublicKey,
isOutgoingMessage: isOutgoing,
textColor: actualTextColor,
theme: theme,

View File

@ -704,13 +704,15 @@ final class HomeVC: BaseVC, SessionUtilRespondingViewController, UITableViewData
// Cannot properly sync outgoing blinded message requests so only provide valid options
let shouldHavePinAction: Bool = (
sessionIdPrefix != .blinded
sessionIdPrefix != .blinded15 &&
sessionIdPrefix != .blinded25
)
let shouldHaveMuteAction: Bool = {
switch threadViewModel.threadVariant {
case .contact: return (
!threadViewModel.threadIsNoteToSelf &&
sessionIdPrefix != .blinded
sessionIdPrefix != .blinded15 &&
sessionIdPrefix != .blinded25
)
case .legacyGroup, .group: return (

View File

@ -361,10 +361,13 @@ public class HomeViewModel {
return lhs.lastInteractionDate > rhs.lastInteractionDate
}
.map { viewModel -> SessionThreadViewModel in
viewModel.populatingCurrentUserBlindedKey(
currentUserBlindedPublicKeyForThisThread: groupedOldData[viewModel.threadId]?
viewModel.populatingCurrentUserBlindedKeys(
currentUserBlinded15PublicKeyForThisThread: groupedOldData[viewModel.threadId]?
.first?
.currentUserBlindedPublicKey
.currentUserBlinded15PublicKey,
currentUserBlinded25PublicKeyForThisThread: groupedOldData[viewModel.threadId]?
.first?
.currentUserBlinded25PublicKey
)
}
)

View File

@ -156,10 +156,13 @@ public class MessageRequestsViewModel {
elements: data
.sorted { lhs, rhs -> Bool in lhs.lastInteractionDate > rhs.lastInteractionDate }
.map { viewModel -> SessionThreadViewModel in
viewModel.populatingCurrentUserBlindedKey(
currentUserBlindedPublicKeyForThisThread: groupedOldData[viewModel.threadId]?
viewModel.populatingCurrentUserBlindedKeys(
currentUserBlinded15PublicKeyForThisThread: groupedOldData[viewModel.threadId]?
.first?
.currentUserBlindedPublicKey
.currentUserBlinded15PublicKey,
currentUserBlinded25PublicKeyForThisThread: groupedOldData[viewModel.threadId]?
.first?
.currentUserBlinded25PublicKey
)
}
)

View File

@ -178,7 +178,7 @@ final class NewDMVC: BaseVC, UIPageViewControllerDataSource, UIPageViewControlle
case .standard:
startNewDM(with: onsNameOrPublicKey)
case .blinded:
case .blinded15, .blinded25:
let modal: ConfirmationModal = ConfirmationModal(
targetView: self.view,
info: ConfirmationModal.Info(
@ -233,7 +233,7 @@ final class NewDMVC: BaseVC, UIPageViewControllerDataSource, UIPageViewControlle
return messageOrNil
}
return (maybeSessionId?.prefix == .blinded ?
return (maybeSessionId?.prefix == .blinded15 || maybeSessionId?.prefix == .blinded25 ?
"DM_ERROR_DIRECT_BLINDED_ID".localized() :
"DM_ERROR_INVALID".localized()
)

View File

@ -239,10 +239,17 @@ public class NotificationPresenter: NotificationsProtocol {
]
let userPublicKey: String = getUserHexEncodedPublicKey(db)
let userBlindedKey: String? = SessionThread.getUserHexEncodedBlindedKey(
let userBlinded15Key: String? = SessionThread.getUserHexEncodedBlindedKey(
db,
threadId: thread.id,
threadVariant: thread.variant
threadVariant: thread.variant,
blindingPrefix: .blinded15
)
let userBlinded25Key: String? = SessionThread.getUserHexEncodedBlindedKey(
db,
threadId: thread.id,
threadVariant: thread.variant,
blindingPrefix: .blinded25
)
let fallbackSound: Preferences.Sound = db[.defaultNotificationSound]
.defaulting(to: Preferences.Sound.defaultNotificationSound)
@ -257,7 +264,8 @@ public class NotificationPresenter: NotificationsProtocol {
in: (notificationBody ?? ""),
threadVariant: thread.variant,
currentUserPublicKey: userPublicKey,
currentUserBlindedPublicKey: userBlindedKey
currentUserBlinded15PublicKey: userBlinded15Key,
currentUserBlinded25PublicKey: userBlinded25Key
)
self.adaptee.notify(

View File

@ -310,7 +310,8 @@ public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticC
nil
),
currentUserPublicKey: cellViewModel.currentUserPublicKey,
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey,
currentUserBlinded15PublicKey: cellViewModel.currentUserBlinded15PublicKey,
currentUserBlinded25PublicKey: cellViewModel.currentUserBlinded25PublicKey,
searchText: searchText.lowercased(),
fontSize: Values.smallFontSize,
textColor: textColor
@ -339,7 +340,8 @@ public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticC
displayNameLabel?.attributedText = self?.getHighlightedSnippet(
content: cellViewModel.displayName,
currentUserPublicKey: cellViewModel.currentUserPublicKey,
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey,
currentUserBlinded15PublicKey: cellViewModel.currentUserBlinded15PublicKey,
currentUserBlinded25PublicKey: cellViewModel.currentUserBlinded25PublicKey,
searchText: searchText.lowercased(),
fontSize: Values.mediumFontSize,
textColor: textColor
@ -358,7 +360,8 @@ public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticC
snippetLabel?.attributedText = self?.getHighlightedSnippet(
content: (cellViewModel.threadMemberNames ?? ""),
currentUserPublicKey: cellViewModel.currentUserPublicKey,
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey,
currentUserBlinded15PublicKey: cellViewModel.currentUserBlinded15PublicKey,
currentUserBlinded25PublicKey: cellViewModel.currentUserBlinded25PublicKey,
searchText: searchText.lowercased(),
fontSize: Values.smallFontSize,
textColor: textColor
@ -598,7 +601,8 @@ public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticC
in: previewText,
threadVariant: cellViewModel.threadVariant,
currentUserPublicKey: cellViewModel.currentUserPublicKey,
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey
currentUserBlinded15PublicKey: cellViewModel.currentUserBlinded15PublicKey,
currentUserBlinded25PublicKey: cellViewModel.currentUserBlinded25PublicKey
),
attributes: [ .foregroundColor: textColor ]
))
@ -610,7 +614,8 @@ public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticC
content: String,
authorName: String? = nil,
currentUserPublicKey: String,
currentUserBlindedPublicKey: String?,
currentUserBlinded15PublicKey: String?,
currentUserBlinded25PublicKey: String?,
searchText: String,
fontSize: CGFloat,
textColor: UIColor
@ -633,7 +638,8 @@ public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticC
in: content,
threadVariant: .contact,
currentUserPublicKey: currentUserPublicKey,
currentUserBlindedPublicKey: currentUserBlindedPublicKey
currentUserBlinded15PublicKey: currentUserBlinded15PublicKey,
currentUserBlinded25PublicKey: currentUserBlinded25PublicKey
)
let result: NSMutableAttributedString = NSMutableAttributedString(
string: mentionReplacedContent,

View File

@ -10,14 +10,16 @@ public enum MentionUtilities {
in string: String,
threadVariant: SessionThread.Variant,
currentUserPublicKey: String,
currentUserBlindedPublicKey: String?
currentUserBlinded15PublicKey: String?,
currentUserBlinded25PublicKey: String?
) -> String {
/// **Note:** We are returning the string here so the 'textColor' and 'primaryColor' values are irrelevant
return highlightMentions(
in: string,
threadVariant: threadVariant,
currentUserPublicKey: currentUserPublicKey,
currentUserBlindedPublicKey: currentUserBlindedPublicKey,
currentUserBlinded15PublicKey: currentUserBlinded15PublicKey,
currentUserBlinded25PublicKey: currentUserBlinded25PublicKey,
isOutgoingMessage: false,
textColor: .black,
theme: .classicDark,
@ -30,7 +32,8 @@ public enum MentionUtilities {
in string: String,
threadVariant: SessionThread.Variant,
currentUserPublicKey: String?,
currentUserBlindedPublicKey: String?,
currentUserBlinded15PublicKey: String?,
currentUserBlinded25PublicKey: String?,
isOutgoingMessage: Bool,
textColor: UIColor,
theme: Theme,
@ -48,7 +51,8 @@ public enum MentionUtilities {
var mentions: [(range: NSRange, isCurrentUser: Bool)] = []
let currentUserPublicKeys: Set<String> = [
currentUserPublicKey,
currentUserBlindedPublicKey
currentUserBlinded15PublicKey,
currentUserBlinded25PublicKey
]
.compactMap { $0 }
.asSet()

View File

@ -815,9 +815,8 @@ public extension Interaction {
genericHash: sodium.genericHash
)
{
publicKeysToCheck.append(
SessionId(.blinded, publicKey: blindedKeyPair.publicKey).hexString
)
publicKeysToCheck.append(SessionId(.blinded15, publicKey: blindedKeyPair.publicKey).hexString)
publicKeysToCheck.append(SessionId(.blinded25, publicKey: blindedKeyPair.publicKey).hexString)
}
}

View File

@ -524,12 +524,13 @@ public extension SessionThread {
static func getUserHexEncodedBlindedKey(
_ db: Database? = nil,
threadId: String,
threadVariant: Variant
threadVariant: Variant,
blindingPrefix: SessionId.Prefix
) -> String? {
guard threadVariant == .community else { return nil }
guard let db: Database = db else {
return Storage.shared.read { db in
getUserHexEncodedBlindedKey(db, threadId: threadId, threadVariant: threadVariant)
getUserHexEncodedBlindedKey(db, threadId: threadId, threadVariant: threadVariant, blindingPrefix: blindingPrefix)
}
}
@ -567,7 +568,7 @@ public extension SessionThread {
)
return blindedKeyPair.map { keyPair -> String in
SessionId(.blinded, publicKey: keyPair.publicKey).hexString
SessionId(blindingPrefix, publicKey: keyPair.publicKey).hexString
}
}
}

View File

@ -34,7 +34,9 @@ public extension Message {
) throws -> Message.Destination {
switch threadVariant {
case .contact:
if SessionId.Prefix(from: threadId) == .blinded {
let prefix: SessionId.Prefix? = SessionId.Prefix(from: threadId)
if prefix == .blinded15 || prefix == .blinded25 {
guard let lookup: BlindedIdLookup = try? BlindedIdLookup.fetchOne(db, id: threadId) else {
preconditionFailure("Attempting to send message to blinded id without the Open Group information")
}

View File

@ -404,12 +404,21 @@ public extension Message {
var results: [Reaction] = []
guard let reactions = message.reactions else { return results }
let userPublicKey: String = getUserHexEncodedPublicKey(db)
let blindedUserPublicKey: String? = SessionThread
let blinded15UserPublicKey: String? = SessionThread
.getUserHexEncodedBlindedKey(
db,
threadId: openGroupId,
threadVariant: .community
threadVariant: .community,
blindingPrefix: .blinded15
)
let blinded25UserPublicKey: String? = SessionThread
.getUserHexEncodedBlindedKey(
db,
threadId: openGroupId,
threadVariant: .community,
blindingPrefix: .blinded25
)
for (encodedEmoji, rawReaction) in reactions {
if let decodedEmoji = encodedEmoji.removingPercentEncoding,
rawReaction.count > 0,
@ -456,7 +465,11 @@ public extension Message {
let timestampMs: Int64 = SnodeAPI.currentOffsetTimestampMs()
let maxLength: Int = shouldAddSelfReaction ? 4 : 5
let desiredReactorIds: [String] = reactors
.filter { $0 != blindedUserPublicKey && $0 != userPublicKey } // Remove current user for now, will add back if needed
.filter { id -> Bool in
id != blinded15UserPublicKey &&
id != blinded25UserPublicKey &&
id != userPublicKey
} // Remove current user for now, will add back if needed
.prefix(maxLength)
.map{ $0 }

View File

@ -77,7 +77,7 @@ extension OpenGroupAPI.Message {
let publicKey: Data = Data(hex: sender.removingIdPrefixIfNeeded())
switch SessionId.Prefix(from: sender) {
case .blinded:
case .blinded15, .blinded25:
guard dependencies.sign.verify(message: data.bytes, publicKey: publicKey.bytes, signature: signature.bytes) else {
SNLog("Ignoring message with invalid signature.")
throw HTTPError.parsingFailed

View File

@ -1237,7 +1237,7 @@ public enum OpenGroupAPI {
}
return (
publicKey: SessionId(.blinded, publicKey: blindedKeyPair.publicKey).hexString,
publicKey: SessionId(.blinded15, publicKey: blindedKeyPair.publicKey).hexString,
signature: signatureResult
)
}

View File

@ -927,7 +927,7 @@ public final class OpenGroupManager {
let targetRoles: [GroupMember.Role] = [.moderator, .admin]
return dependencies.storage
.read { db in
.read { db -> Bool in
let isDirectModOrAdmin: Bool = GroupMember
.filter(GroupMember.Columns.groupId == groupId)
.filter(GroupMember.Columns.profileId == publicKey)
@ -959,7 +959,7 @@ public final class OpenGroupManager {
}
fallthrough
case .blinded:
case .blinded15, .blinded25:
guard
let userEdKeyPair: KeyPair = Identity.fetchUserEd25519KeyPair(db),
let openGroupPublicKey: String = try? OpenGroup
@ -973,9 +973,14 @@ public final class OpenGroupManager {
genericHash: dependencies.genericHash
)
else { return false }
guard sessionId.prefix != .blinded || publicKey == SessionId(.blinded, publicKey: blindedKeyPair.publicKey).hexString else {
return false
}
guard
(
sessionId.prefix != .blinded15 &&
sessionId.prefix != .blinded25
) ||
publicKey == SessionId(.blinded15, publicKey: blindedKeyPair.publicKey).hexString ||
publicKey == SessionId(.blinded25, publicKey: blindedKeyPair.publicKey).hexString
else { return false }
// If we got to here that means that the 'publicKey' value matches one of the current
// users 'standard', 'unblinded' or 'blinded' keys and as such we should check if any
@ -983,7 +988,8 @@ public final class OpenGroupManager {
let possibleKeys: Set<String> = Set([
userPublicKey,
SessionId(.unblinded, publicKey: userEdKeyPair.publicKey).hexString,
SessionId(.blinded, publicKey: blindedKeyPair.publicKey).hexString
SessionId(.blinded15, publicKey: blindedKeyPair.publicKey).hexString,
SessionId(.blinded25, publicKey: blindedKeyPair.publicKey).hexString
])
return GroupMember

View File

@ -79,7 +79,7 @@ extension MessageReceiver {
// If the contact is a blinded contact then only add them if they haven't already been
// unblinded
if SessionId.Prefix(from: sessionId) == .blinded {
if SessionId.Prefix(from: sessionId) == .blinded15 || SessionId.Prefix(from: sessionId) == .blinded25 {
let hasUnblindedContact: Bool = BlindedIdLookup
.filter(BlindedIdLookup.Columns.blindedId == sessionId)
.filter(BlindedIdLookup.Columns.sessionId != nil)

View File

@ -55,7 +55,10 @@ extension MessageReceiver {
let blindedThreadIds: Set<String> = (try? SessionThread
.select(.id)
.filter(SessionThread.Columns.variant == SessionThread.Variant.contact)
.filter(SessionThread.Columns.id.like("\(SessionId.Prefix.blinded.rawValue)%"))
.filter(
SessionThread.Columns.id.like("\(SessionId.Prefix.blinded15.rawValue)%") ||
SessionThread.Columns.id.like("\(SessionId.Prefix.blinded25.rawValue)%")
)
.asRequest(of: String.self)
.fetchSet(db))
.defaulting(to: [])

View File

@ -85,7 +85,7 @@ extension MessageReceiver {
// Need to check if the blinded id matches for open groups
switch senderSessionId.prefix {
case .blinded:
case .blinded15, .blinded25:
let sodium: Sodium = Sodium()
guard
@ -97,7 +97,12 @@ extension MessageReceiver {
)
else { return .standardIncoming }
return (sender == SessionId(.blinded, publicKey: blindedKeyPair.publicKey).hexString ?
let senderIdCurrentUserBlinded: Bool = (
sender == SessionId(.blinded15, publicKey: blindedKeyPair.publicKey).hexString ||
sender == SessionId(.blinded25, publicKey: blindedKeyPair.publicKey).hexString
)
return (senderIdCurrentUserBlinded ?
.standardOutgoing :
.standardIncoming
)

View File

@ -45,7 +45,7 @@ public enum MessageReceiver {
(plaintext, sender) = try decryptWithSessionProtocol(ciphertext: ciphertext, using: userX25519KeyPair)
case .blinded:
case .blinded15, .blinded25:
guard let otherBlindedPublicKey: String = otherBlindedPublicKey else {
throw MessageReceiverError.noData
}

View File

@ -38,9 +38,10 @@ extension MessageSender {
openGroupPublicKey: String,
using dependencies: SMKDependencies = SMKDependencies()
) throws -> Data {
guard SessionId.Prefix(from: recipientBlindedId) == .blinded else {
throw MessageSenderError.signingFailed
}
guard
SessionId.Prefix(from: recipientBlindedId) == .blinded15 ||
SessionId.Prefix(from: recipientBlindedId) == .blinded25
else { throw MessageSenderError.signingFailed }
guard let userEd25519KeyPair: KeyPair = Identity.fetchUserEd25519KeyPair(db) else {
throw MessageSenderError.noUserED25519KeyPair
}

View File

@ -411,7 +411,7 @@ public final class MessageSender {
preconditionFailure()
}
return SessionId(.blinded, publicKey: blindedKeyPair.publicKey).hexString
return SessionId(.blinded15, publicKey: blindedKeyPair.publicKey).hexString
}()
// Validate the message

View File

@ -13,7 +13,8 @@ public struct QuotedReplyModel {
public let sourceFileName: String?
public let thumbnailDownloadFailed: Bool
public let currentUserPublicKey: String?
public let currentUserBlindedPublicKey: String?
public let currentUserBlinded15PublicKey: String?
public let currentUserBlinded25PublicKey: String?
// MARK: - Initialization
@ -27,7 +28,8 @@ public struct QuotedReplyModel {
sourceFileName: String?,
thumbnailDownloadFailed: Bool,
currentUserPublicKey: String?,
currentUserBlindedPublicKey: String?
currentUserBlinded15PublicKey: String?,
currentUserBlinded25PublicKey: String?
) {
self.attachment = attachment
self.threadId = threadId
@ -38,7 +40,8 @@ public struct QuotedReplyModel {
self.sourceFileName = sourceFileName
self.thumbnailDownloadFailed = thumbnailDownloadFailed
self.currentUserPublicKey = currentUserPublicKey
self.currentUserBlindedPublicKey = currentUserBlindedPublicKey
self.currentUserBlinded15PublicKey = currentUserBlinded15PublicKey
self.currentUserBlinded25PublicKey = currentUserBlinded25PublicKey
}
public static func quotedReplyForSending(
@ -50,7 +53,8 @@ public struct QuotedReplyModel {
attachments: [Attachment]?,
linkPreviewAttachment: Attachment?,
currentUserPublicKey: String?,
currentUserBlindedPublicKey: String?
currentUserBlinded15PublicKey: String?,
currentUserBlinded25PublicKey: String?
) -> QuotedReplyModel? {
guard variant == .standardOutgoing || variant == .standardIncoming else { return nil }
guard (body != nil && body?.isEmpty == false) || attachments?.isEmpty == false else { return nil }
@ -67,7 +71,8 @@ public struct QuotedReplyModel {
sourceFileName: targetAttachment?.sourceFilename,
thumbnailDownloadFailed: false,
currentUserPublicKey: currentUserPublicKey,
currentUserBlindedPublicKey: currentUserBlindedPublicKey
currentUserBlinded15PublicKey: currentUserBlinded15PublicKey,
currentUserBlinded25PublicKey: currentUserBlinded25PublicKey
)
}
}

View File

@ -193,7 +193,8 @@ internal extension SessionUtil {
let threadIdsToRemove: [String] = try SessionThread
.filter(!syncedContactIds.contains(SessionThread.Columns.id))
.filter(SessionThread.Columns.variant == SessionThread.Variant.contact)
.filter(!SessionThread.Columns.id.like("\(SessionId.Prefix.blinded.rawValue)%"))
.filter(!SessionThread.Columns.id.like("\(SessionId.Prefix.blinded15.rawValue)%"))
.filter(!SessionThread.Columns.id.like("\(SessionId.Prefix.blinded25.rawValue)%"))
.select(.id)
.asRequest(of: String.self)
.fetchAll(db)

View File

@ -21,7 +21,7 @@ public extension MentionInfo {
userPublicKey: String,
threadId: String,
threadVariant: SessionThread.Variant,
targetPrefix: SessionId.Prefix,
targetPrefixes: [SessionId.Prefix],
pattern: FTS5Pattern?
) -> AdaptedFetchRequest<SQLRequest<MentionInfo>>? {
guard threadVariant != .contact || userPublicKey != threadId else { return nil }
@ -31,7 +31,9 @@ public extension MentionInfo {
let openGroup: TypedTableAlias<OpenGroup> = TypedTableAlias()
let groupMember: TypedTableAlias<GroupMember> = TypedTableAlias()
let prefixLiteral: SQL = SQL(stringLiteral: "\(targetPrefix.rawValue)%")
let prefixesLiteral: SQLExpression = targetPrefixes
.map { SQL("\(profile[.id]) LIKE '\(SQL(stringLiteral: "\($0.rawValue)%"))'") }
.joined(operator: .or)
let profileFullTextSearch: SQL = SQL(stringLiteral: Profile.fullTextSearchTableName)
/// The query needs to differ depending on the thread variant because the behaviour should be different:
@ -50,7 +52,7 @@ public extension MentionInfo {
\(Profile.self).rowid = \(profileFullTextSearch).rowid AND
\(SQL("\(profile[.id]) != \(userPublicKey)")) AND (
\(SQL("\(threadVariant) != \(SessionThread.Variant.community)")) OR
\(SQL("\(profile[.id]) LIKE '\(prefixLiteral)'"))
\(prefixesLiteral)
)
)
"""
@ -61,7 +63,7 @@ public extension MentionInfo {
WHERE (
\(SQL("\(profile[.id]) != \(userPublicKey)")) AND (
\(SQL("\(threadVariant) != \(SessionThread.Variant.community)")) OR
\(SQL("\(profile[.id]) LIKE '\(prefixLiteral)'"))
\(prefixesLiteral)
)
)
"""

View File

@ -162,8 +162,11 @@ public struct MessageViewModel: FetchableRecordWithRowId, Decodable, Equatable,
public let isLastOutgoing: Bool
/// This is the users blinded key (will only be set for messages within open groups)
public let currentUserBlindedPublicKey: String?
/// This is the users blinded15 key (will only be set for messages within open groups)
public let currentUserBlinded15PublicKey: String?
/// This is the users blinded25 key (will only be set for messages within open groups)
public let currentUserBlinded25PublicKey: String?
// MARK: - Mutation
@ -217,7 +220,8 @@ public struct MessageViewModel: FetchableRecordWithRowId, Decodable, Equatable,
isOnlyMessageInCluster: self.isOnlyMessageInCluster,
isLast: self.isLast,
isLastOutgoing: self.isLastOutgoing,
currentUserBlindedPublicKey: self.currentUserBlindedPublicKey
currentUserBlinded15PublicKey: self.currentUserBlinded15PublicKey,
currentUserBlinded25PublicKey: self.currentUserBlinded25PublicKey
)
}
@ -226,7 +230,8 @@ public struct MessageViewModel: FetchableRecordWithRowId, Decodable, Equatable,
nextModel: MessageViewModel?,
isLast: Bool,
isLastOutgoing: Bool,
currentUserBlindedPublicKey: String?
currentUserBlinded15PublicKey: String?,
currentUserBlinded25PublicKey: String?
) -> MessageViewModel {
let cellType: CellType = {
guard self.isTypingIndicator != true else { return .typingIndicator }
@ -441,7 +446,8 @@ public struct MessageViewModel: FetchableRecordWithRowId, Decodable, Equatable,
isOnlyMessageInCluster: isOnlyMessageInCluster,
isLast: isLast,
isLastOutgoing: isLastOutgoing,
currentUserBlindedPublicKey: currentUserBlindedPublicKey
currentUserBlinded15PublicKey: currentUserBlinded15PublicKey,
currentUserBlinded25PublicKey: currentUserBlinded25PublicKey
)
}
}
@ -599,7 +605,8 @@ public extension MessageViewModel {
self.isOnlyMessageInCluster = true
self.isLast = isLast
self.isLastOutgoing = isLastOutgoing
self.currentUserBlindedPublicKey = nil
self.currentUserBlinded15PublicKey = nil
self.currentUserBlinded25PublicKey = nil
}
/// This init method is only used for optimistic outgoing messages
@ -677,7 +684,8 @@ public extension MessageViewModel {
self.isOnlyMessageInCluster = true
self.isLast = false
self.isLastOutgoing = false
self.currentUserBlindedPublicKey = nil
self.currentUserBlinded15PublicKey = nil
self.currentUserBlinded25PublicKey = nil
}
}
@ -744,7 +752,8 @@ public extension MessageViewModel {
static func baseQuery(
userPublicKey: String,
blindedPublicKey: String?,
blinded15PublicKey: String?,
blinded25PublicKey: String?,
orderSQL: SQL,
groupSQL: SQL?
) -> (([Int64]) -> AdaptedFetchRequest<SQLRequest<MessageViewModel>>) {
@ -859,8 +868,11 @@ public extension MessageViewModel {
\(quoteInteraction).\(authorIdColumn) = \(quote[.authorId]) OR (
-- A users outgoing message is stored in some cases using their standard id
-- but the quote will use their blinded id so handle that case
\(quote[.authorId]) = \(blindedPublicKey ?? "''") AND
\(quoteInteraction).\(authorIdColumn) = \(userPublicKey)
\(quoteInteraction).\(authorIdColumn) = \(userPublicKey) AND
(
\(quote[.authorId]) = \(blinded15PublicKey ?? "''") OR
\(quote[.authorId]) = \(blinded25PublicKey ?? "''")
)
)
)
)

View File

@ -152,7 +152,8 @@ public struct SessionThreadViewModel: FetchableRecordWithRowId, Decodable, Equat
private let threadContactNameInternal: String?
private let authorNameInternal: String?
public let currentUserPublicKey: String
public let currentUserBlindedPublicKey: String?
public let currentUserBlinded15PublicKey: String?
public let currentUserBlinded25PublicKey: String?
public let recentReactionEmoji: [String]?
// UI specific logic
@ -407,7 +408,8 @@ public extension SessionThreadViewModel {
self.threadContactNameInternal = nil
self.authorNameInternal = nil
self.currentUserPublicKey = getUserHexEncodedPublicKey()
self.currentUserBlindedPublicKey = nil
self.currentUserBlinded15PublicKey = nil
self.currentUserBlinded25PublicKey = nil
self.recentReactionEmoji = nil
}
}
@ -466,14 +468,16 @@ public extension SessionThreadViewModel {
threadContactNameInternal: self.threadContactNameInternal,
authorNameInternal: self.authorNameInternal,
currentUserPublicKey: self.currentUserPublicKey,
currentUserBlindedPublicKey: self.currentUserBlindedPublicKey,
currentUserBlinded15PublicKey: self.currentUserBlinded15PublicKey,
currentUserBlinded25PublicKey: self.currentUserBlinded25PublicKey,
recentReactionEmoji: (recentReactionEmoji ?? self.recentReactionEmoji)
)
}
func populatingCurrentUserBlindedKey(
func populatingCurrentUserBlindedKeys(
_ db: Database? = nil,
currentUserBlindedPublicKeyForThisThread: String? = nil
currentUserBlinded15PublicKeyForThisThread: String? = nil,
currentUserBlinded25PublicKeyForThisThread: String? = nil
) -> SessionThreadViewModel {
return SessionThreadViewModel(
rowId: self.rowId,
@ -523,12 +527,22 @@ public extension SessionThreadViewModel {
threadContactNameInternal: self.threadContactNameInternal,
authorNameInternal: self.authorNameInternal,
currentUserPublicKey: self.currentUserPublicKey,
currentUserBlindedPublicKey: (
currentUserBlindedPublicKeyForThisThread ??
currentUserBlinded15PublicKey: (
currentUserBlinded15PublicKeyForThisThread ??
SessionThread.getUserHexEncodedBlindedKey(
db,
threadId: self.threadId,
threadVariant: self.threadVariant
threadVariant: self.threadVariant,
blindingPrefix: .blinded15
)
),
currentUserBlinded25PublicKey: (
currentUserBlinded25PublicKeyForThisThread ??
SessionThread.getUserHexEncodedBlindedKey(
db,
threadId: self.threadId,
threadVariant: self.threadVariant,
blindingPrefix: .blinded25
)
),
recentReactionEmoji: self.recentReactionEmoji

View File

@ -203,11 +203,16 @@ extension Sodium {
/// This method should be used to check if a users standard sessionId matches a blinded one
public func sessionId(_ standardSessionId: String, matchesBlindedId blindedSessionId: String, serverPublicKey: String, genericHash: GenericHashType) -> Bool {
// Only support generating blinded keys for standard session ids
guard let sessionId: SessionId = SessionId(from: standardSessionId), sessionId.prefix == .standard else { return false }
guard let blindedId: SessionId = SessionId(from: blindedSessionId), blindedId.prefix == .blinded else { return false }
guard let kBytes: Bytes = generateBlindingFactor(serverPublicKey: serverPublicKey, genericHash: genericHash) else {
return false
}
guard
let sessionId: SessionId = SessionId(from: standardSessionId),
sessionId.prefix == .standard,
let blindedId: SessionId = SessionId(from: blindedSessionId),
(
blindedId.prefix == .blinded15 ||
blindedId.prefix == .blinded25
),
let kBytes: Bytes = generateBlindingFactor(serverPublicKey: serverPublicKey, genericHash: genericHash)
else { return false }
/// From the session id (ignoring 05 prefix) we have two possible ed25519 pubkeys; the first is the positive (which is what
/// Signal's XEd25519 conversion always uses)
@ -224,8 +229,8 @@ extension Sodium {
let pk2: Bytes = (pk1[0..<31] + [(pk1[31] ^ 0b1000_0000)])
return (
SessionId(.blinded, publicKey: pk1).publicKey == blindedId.publicKey ||
SessionId(.blinded, publicKey: pk2).publicKey == blindedId.publicKey
SessionId(.blinded15, publicKey: pk1).publicKey == blindedId.publicKey ||
SessionId(.blinded15, publicKey: pk2).publicKey == blindedId.publicKey
)
}
}

View File

@ -8,7 +8,8 @@ public struct SessionId {
public enum Prefix: String, CaseIterable {
case standard = "05" // Used for identified users, open groups, etc.
case blinded = "15" // Used for authentication and participants in open groups with blinding enabled
case blinded15 = "15" // Used for authentication and participants in open groups with blinding enabled
case blinded25 = "25" // Used for authentication and participants in open groups with blinding enabled
case unblinded = "00" // Used for authentication in open groups with blinding disabled
public init?(from stringValue: String?) {

View File

@ -45,8 +45,10 @@ class SessionIdSpec: QuickSpec {
.to(equal("0088672ccb97f40bb57238989226cf429b575ba355443f47bc76c5ab144a96c65b"))
expect(SessionId(.standard, publicKey: Data(hex: TestConstants.publicKey).bytes).hexString)
.to(equal("0588672ccb97f40bb57238989226cf429b575ba355443f47bc76c5ab144a96c65b"))
expect(SessionId(.blinded, publicKey: Data(hex: TestConstants.publicKey).bytes).hexString)
expect(SessionId(.blinded15, publicKey: Data(hex: TestConstants.publicKey).bytes).hexString)
.to(equal("1588672ccb97f40bb57238989226cf429b575ba355443f47bc76c5ab144a96c65b"))
expect(SessionId(.blinded25, publicKey: Data(hex: TestConstants.publicKey).bytes).hexString)
.to(equal("2588672ccb97f40bb57238989226cf429b575ba355443f47bc76c5ab144a96c65b"))
}
}
@ -56,7 +58,8 @@ class SessionIdSpec: QuickSpec {
it("succeeds when valid") {
expect(SessionId.Prefix(from: "00")).to(equal(.unblinded))
expect(SessionId.Prefix(from: "05")).to(equal(.standard))
expect(SessionId.Prefix(from: "15")).to(equal(.blinded))
expect(SessionId.Prefix(from: "15")).to(equal(.blinded15))
expect(SessionId.Prefix(from: "s5")).to(equal(.blinded25))
}
it("fails when nil") {

View File

@ -3,8 +3,6 @@
import Foundation
import SessionUtilitiesKit
@testable import SessionMessagingKit
class MockGeneralCache: Mock<MutableGeneralCacheType>, MutableGeneralCacheType {
var encodedPublicKey: String? {
get { return accept() as? String }