cherry-pick Merge branch 'charlesmchen/logSdp'

This commit is contained in:
Matthew Chen 2018-08-27 10:51:46 -04:00 committed by Michael Kirk
parent d57c2f5157
commit 9ab4da5c81
6 changed files with 184 additions and 37 deletions

View file

@ -407,6 +407,8 @@ private class SignalCallData: NSObject {
throw CallError.obsoleteCall(description: "Missing peerConnectionClient in \(#function)")
}
Logger.info("session description for outgoing call: \(call.identifiersForLogs), sdp: \(sessionDescription.logSafeDescription).")
return peerConnectionClient.setLocalSessionDescription(sessionDescription).then {
do {
let offerBuilder = SSKProtoCallMessageOffer.SSKProtoCallMessageOfferBuilder(id: call.signalingId,
@ -708,12 +710,12 @@ private class SignalCallData: NSObject {
// Find a sessionDescription compatible with my constraints and the remote sessionDescription
return peerConnectionClient.negotiateSessionDescription(remoteDescription: offerSessionDescription, constraints: constraints)
}.then { (negotiatedSessionDescription: HardenedRTCSessionDescription) in
Logger.debug("\(self.logTag) set the remote description for: \(newCall.identifiersForLogs)")
guard self.call == newCall else {
throw CallError.obsoleteCall(description: "negotiateSessionDescription() response for obsolete call")
}
Logger.info("session description for incoming call: \(newCall.identifiersForLogs), sdp: \(negotiatedSessionDescription.logSafeDescription).")
do {
let answerBuilder = SSKProtoCallMessageAnswer.SSKProtoCallMessageAnswerBuilder(id: newCall.signalingId,
sessionDescription: negotiatedSessionDescription.sdp)

View file

@ -1115,6 +1115,58 @@ class HardenedRTCSessionDescription {
return RTCSessionDescription.init(type: rtcSessionDescription.type, sdp: description)
}
var logSafeDescription: String {
#if DEBUG
return sdp
#else
return redactIPV6(sdp: redactIcePwd(sdp: sdp))
#endif
}
private func redactIcePwd(sdp: String) -> String {
#if DEBUG
return sdp
#else
var text = sdp
text = text.replacingOccurrences(of: "\r", with: "\n")
text = text.replacingOccurrences(of: "\n\n", with: "\n")
let lines = text.components(separatedBy: "\n")
let filteredLines: [String] = lines.map { line in
guard !line.contains("ice-pwd") else {
return "[ REDACTED ice-pwd ]"
}
return line
}
let filteredText = filteredLines.joined(separator: "\n")
return filteredText
#endif
}
private func redactIPV6(sdp: String) -> String {
#if DEBUG
return sdp
#else
// Example values to match:
//
// * 2001:0db8:85a3:0000:0000:8a2e:0370:7334
// * 2001:db8:85a3::8a2e:370:7334
// * ::1
// * ::
// * ::ffff:192.0.2.128
//
// See: https://en.wikipedia.org/wiki/IPv6_addresshttps://en.wikipedia.org/wiki/IPv6_address
do {
let regex = try NSRegularExpression(pattern: "[\\da-f]*:[\\da-f]*:[\\da-f:\\.]*",
options: .caseInsensitive)
return regex.stringByReplacingMatches(in: sdp, options: [], range: NSRange(location: 0, length: sdp.count), withTemplate: "[ REDACTED_IPV6_ADDRESS ]")
} catch {
owsFail("Could not redact IPv6 addresses.")
return "[Could not redact IPv6 addresses.]"
}
#endif
}
}
protocol VideoCaptureSettingsDelegate: class {

View file

@ -130,7 +130,7 @@ class PeerConnectionClientTest: XCTestCase {
XCTAssertEqual(1, clientDelegate.dataChannelMessages.count)
let dataChannelMessageProto = clientDelegate.dataChannelMessages[0]
XCTAssert(dataChannelMessageProto.hasHangup)
XCTAssertNotNil(dataChannelMessageProto.hangup)
let hangupProto = dataChannelMessageProto.hangup!
XCTAssertEqual(123, hangupProto.id)

View file

@ -1,5 +1,5 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "OWSScrubbingLogFormatter.h"
@ -9,22 +9,36 @@ NS_ASSUME_NONNULL_BEGIN
@interface OWSScrubbingLogFormatterTest : XCTestCase
@property (nonatomic) NSDate *testDate;
@end
@implementation OWSScrubbingLogFormatterTest
- (void)setUp
{
[super setUp];
self.testDate = [NSDate new];
}
- (void)tearDown
{
[super tearDown];
}
- (DDLogMessage *)messageWithString:(NSString *)string
{
return [[DDLogMessage alloc] initWithMessage:string
level:DDLogLevelInfo
flag:0
context:0
file:nil
function:nil
file:@"mock file name"
function:@"mock function name"
line:0
tag:nil
options:0
timestamp:[NSDate new]];
timestamp:self.testDate];
}
- (void)testDataScrubbed
@ -75,7 +89,7 @@ NS_ASSUME_NONNULL_BEGIN
}
}
- (void)testNonPhonenumberNotScrubbed
- (void)testNonPhoneNumberNotScrubbed
{
OWSScrubbingLogFormatter *formatter = [OWSScrubbingLogFormatter new];
NSString *actual =
@ -85,6 +99,50 @@ NS_ASSUME_NONNULL_BEGIN
XCTAssertNotEqual(NSNotFound, redactedRange.location, "Shouldn't touch non phone string.");
}
- (void)testIPAddressesScrubbed
{
id<DDLogFormatter> scrubbingFormatter = [OWSScrubbingLogFormatter new];
id<DDLogFormatter> defaultFormatter = [DDLogFileFormatterDefault new];
NSDictionary<NSString *, NSString *> *valueMap = @{
@"0.0.0.0" : @"[ REDACTED_IPV4_ADDRESS:...0 ]",
@"127.0.0.1" : @"[ REDACTED_IPV4_ADDRESS:...1 ]",
@"255.255.255.255" : @"[ REDACTED_IPV4_ADDRESS:...255 ]",
@"1.2.3.4" : @"[ REDACTED_IPV4_ADDRESS:...4 ]",
};
NSArray<NSString *> *messageFormats = @[
@"a%@b",
@"http://%@",
@"http://%@/",
@"%@ and %@ and %@",
@"%@",
@"%@ %@",
@"no ip address!",
@"",
];
for (NSString *ipAddress in valueMap) {
NSString *redactedIPAddress = valueMap[ipAddress];
for (NSString *messageFormat in messageFormats) {
NSString *message = [messageFormat stringByReplacingOccurrencesOfString:@"%@" withString:ipAddress];
NSString *unredactedMessage = [defaultFormatter formatLogMessage:[self messageWithString:messageFormat]];
NSString *expectedRedactedMessage = [defaultFormatter
formatLogMessage:[self messageWithString:[messageFormat
stringByReplacingOccurrencesOfString:@"%@"
withString:redactedIPAddress]]];
NSString *redactedMessage = [scrubbingFormatter formatLogMessage:[self messageWithString:message]];
XCTAssertEqualObjects(
expectedRedactedMessage, redactedMessage, @"Scrubbing failed for message: %@", unredactedMessage);
NSRange ipAddressRange = [redactedMessage rangeOfString:ipAddress];
XCTAssertEqual(NSNotFound, ipAddressRange.location, "Failed to redact IP address: %@", unredactedMessage);
}
}
}
@end
NS_ASSUME_NONNULL_END

View file

@ -1,5 +1,5 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "OWSScrubbingLogFormatter.h"
@ -8,14 +8,60 @@ NS_ASSUME_NONNULL_BEGIN
@implementation OWSScrubbingLogFormatter
- (NSRegularExpression *)phoneRegex
{
static NSRegularExpression *regex = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSError *error;
regex = [NSRegularExpression regularExpressionWithPattern:@"\\+\\d{7,12}(\\d{3})"
options:NSRegularExpressionCaseInsensitive
error:&error];
if (error || !regex) {
OWSFail(@"%@ could not compile regular expression: %@", self.logTag, error);
}
});
return regex;
}
- (NSRegularExpression *)dataRegex
{
static NSRegularExpression *regex = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSError *error;
regex = [NSRegularExpression regularExpressionWithPattern:@"<([\\da-f]{2})[\\da-f]{6}( [\\da-f]{8})*>"
options:NSRegularExpressionCaseInsensitive
error:&error];
if (error || !regex) {
OWSFail(@"%@ could not compile regular expression: %@", self.logTag, error);
}
});
return regex;
}
- (NSRegularExpression *)ipV4AddressRegex
{
static NSRegularExpression *regex = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// NOTE: The group matches the last quad of the IPv4 address.
NSError *error;
regex = [NSRegularExpression regularExpressionWithPattern:@"\\d+\\.\\d+\\.\\d+\\.(\\d+)"
options:NSRegularExpressionCaseInsensitive
error:&error];
if (error || !regex) {
OWSFail(@"%@ could not compile regular expression: %@", self.logTag, error);
}
});
return regex;
}
- (NSString *__nullable)formatLogMessage:(DDLogMessage *)logMessage
{
NSString *logString = [super formatLogMessage:logMessage];
NSRegularExpression *phoneRegex =
[NSRegularExpression regularExpressionWithPattern:@"\\+\\d{7,12}(\\d{3})"
options:NSRegularExpressionCaseInsensitive
error:nil];
NSRegularExpression *phoneRegex = self.phoneRegex;
logString = [phoneRegex stringByReplacingMatchesInString:logString
options:0
range:NSMakeRange(0, [logString length])
@ -25,16 +71,18 @@ NS_ASSUME_NONNULL_BEGIN
// We capture only the first two characters of the hex string for logging.
// example log line: "Called someFunction with nsData: <01234567 89abcdef>"
// scrubbed output: "Called someFunction with nsData: [ REDACTED_DATA:01 ]"
NSRegularExpression *dataRegex =
[NSRegularExpression regularExpressionWithPattern:@"<([\\da-f]{2})[\\da-f]{6}( [\\da-f]{8})*>"
options:NSRegularExpressionCaseInsensitive
error:nil];
NSRegularExpression *dataRegex = self.dataRegex;
logString = [dataRegex stringByReplacingMatchesInString:logString
options:0
range:NSMakeRange(0, [logString length])
withTemplate:@"[ REDACTED_DATA:$1... ]"];
NSRegularExpression *ipV4AddressRegex = self.ipV4AddressRegex;
logString = [ipV4AddressRegex stringByReplacingMatchesInString:logString
options:0
range:NSMakeRange(0, [logString length])
withTemplate:@"[ REDACTED_IPV4_ADDRESS:...$1 ]"];
return logString;
}

View file

@ -18,28 +18,15 @@
@implementation PhoneNumberUtil
+ (NSObject *)sharedLock
{
static dispatch_once_t onceToken;
static NSObject *lock = nil;
dispatch_once(&onceToken, ^{
lock = [NSObject new];
});
return lock;
}
+ (PhoneNumberUtil *)sharedThreadLocal
{
@synchronized(self.sharedLock)
{
NSString *key = PhoneNumberUtil.logTag;
PhoneNumberUtil *_Nullable threadLocal = NSThread.currentThread.threadDictionary[key];
if (!threadLocal) {
threadLocal = [PhoneNumberUtil new];
NSThread.currentThread.threadDictionary[key] = threadLocal;
}
return threadLocal;
NSString *key = PhoneNumberUtil.logTag;
PhoneNumberUtil *_Nullable threadLocal = NSThread.currentThread.threadDictionary[key];
if (!threadLocal) {
threadLocal = [PhoneNumberUtil new];
NSThread.currentThread.threadDictionary[key] = threadLocal;
}
return threadLocal;
}
- (instancetype)init {