diff --git a/CHANGELOG.md b/CHANGELOG.md index a12d1b4bb..6f7013790 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Changelog ### Bug Fixes * Device info serialisation fix: adds fallback empty dictionary for serialisation [#279](https://github.com/bugsnag/bugsnag-cocoa/pull/279) +* Enforce requiring API key to initialise notifier [#280](https://github.com/bugsnag/bugsnag-cocoa/pull/280) ## 5.15.5 (25 Apr 2018) diff --git a/Source/Bugsnag.m b/Source/Bugsnag.m index 22692ea41..f28394c2f 100644 --- a/Source/Bugsnag.m +++ b/Source/Bugsnag.m @@ -51,9 +51,13 @@ + (void)startBugsnagWithApiKey:(NSString *)apiKey { + (void)startBugsnagWithConfiguration:(BugsnagConfiguration *)configuration { @synchronized(self) { - bsg_g_bugsnag_notifier = - [[BugsnagNotifier alloc] initWithConfiguration:configuration]; - [bsg_g_bugsnag_notifier start]; + if ([configuration hasValidApiKey]) { + bsg_g_bugsnag_notifier = + [[BugsnagNotifier alloc] initWithConfiguration:configuration]; + [bsg_g_bugsnag_notifier start]; + } else { + bsg_log_err(@"Bugsnag not initialized - a valid API key must be supplied."); + } } } @@ -73,75 +77,87 @@ + (BugsnagNotifier *)notifier { } + (void)notify:(NSException *)exception { - [self.notifier notifyException:exception - block:^(BugsnagCrashReport *_Nonnull report) { - report.depth += 2; - }]; + if ([self bugsnagStarted]) { + [self.notifier notifyException:exception + block:^(BugsnagCrashReport *_Nonnull report) { + report.depth += 2; + }]; + } } + (void)notify:(NSException *)exception block:(BugsnagNotifyBlock)block { - [[self notifier] notifyException:exception - block:^(BugsnagCrashReport *_Nonnull report) { - report.depth += 2; - - if (block) { - block(report); - } - }]; + if ([self bugsnagStarted]) { + [[self notifier] notifyException:exception + block:^(BugsnagCrashReport *_Nonnull report) { + report.depth += 2; + + if (block) { + block(report); + } + }]; + } } + (void)notifyError:(NSError *)error { - [self.notifier notifyError:error - block:^(BugsnagCrashReport *_Nonnull report) { - report.depth += 2; - }]; + if ([self bugsnagStarted]) { + [self.notifier notifyError:error + block:^(BugsnagCrashReport *_Nonnull report) { + report.depth += 2; + }]; + } } + (void)notifyError:(NSError *)error block:(BugsnagNotifyBlock)block { - [[self notifier] notifyError:error - block:^(BugsnagCrashReport *_Nonnull report) { - report.depth += 2; - - if (block) { - block(report); - } - }]; + if ([self bugsnagStarted]) { + [[self notifier] notifyError:error + block:^(BugsnagCrashReport *_Nonnull report) { + report.depth += 2; + + if (block) { + block(report); + } + }]; + } } + (void)notify:(NSException *)exception withData:(NSDictionary *)metaData { - - [[self notifier] - notifyException:exception - block:^(BugsnagCrashReport *_Nonnull report) { - report.depth += 2; - report.metaData = [metaData - BSG_mergedInto:[self.notifier.configuration - .metaData toDictionary]]; - }]; + if ([self bugsnagStarted]) { + [[self notifier] + notifyException:exception + block:^(BugsnagCrashReport *_Nonnull report) { + report.depth += 2; + report.metaData = [metaData + BSG_mergedInto:[self.notifier.configuration + .metaData toDictionary]]; + }]; + } } + (void)notify:(NSException *)exception withData:(NSDictionary *)metaData atSeverity:(NSString *)severity { - - [[self notifier] - notifyException:exception - atSeverity:BSGParseSeverity(severity) - block:^(BugsnagCrashReport *_Nonnull report) { - report.depth += 2; - report.metaData = [metaData - BSG_mergedInto:[self.notifier.configuration - .metaData toDictionary]]; - report.severity = BSGParseSeverity(severity); - }]; + if ([self bugsnagStarted]) { + [[self notifier] + notifyException:exception + atSeverity:BSGParseSeverity(severity) + block:^(BugsnagCrashReport *_Nonnull report) { + report.depth += 2; + report.metaData = [metaData + BSG_mergedInto:[self.notifier.configuration + .metaData toDictionary]]; + report.severity = BSGParseSeverity(severity); + }]; + } } + (void)internalClientNotify:(NSException *_Nonnull)exception withData:(NSDictionary *_Nullable)metaData block:(BugsnagNotifyBlock _Nullable)block { - [self.notifier internalClientNotify:exception - withData:metaData - block:block]; + if ([self bugsnagStarted]) { + [self.notifier internalClientNotify:exception + withData:metaData + block:block]; + } } + (void)addAttribute:(NSString *)attributeName @@ -161,7 +177,7 @@ + (void)clearTabWithName:(NSString *)tabName { } + (BOOL)bugsnagStarted { - if (self.notifier == nil) { + if (!self.notifier.started) { bsg_log_err(@"Ensure you have started Bugsnag with startWithApiKey: " @"before calling any other Bugsnag functions."); @@ -171,31 +187,43 @@ + (BOOL)bugsnagStarted { } + (void)leaveBreadcrumbWithMessage:(NSString *)message { - [self leaveBreadcrumbWithBlock:^(BugsnagBreadcrumb *_Nonnull crumbs) { - crumbs.metadata = @{BSGKeyMessage : message}; - }]; + if ([self bugsnagStarted]) { + [self leaveBreadcrumbWithBlock:^(BugsnagBreadcrumb *_Nonnull crumbs) { + crumbs.metadata = @{BSGKeyMessage: message}; + }]; + } } + (void)leaveBreadcrumbWithBlock: (void (^_Nonnull)(BugsnagBreadcrumb *_Nonnull))block { - [self.notifier addBreadcrumbWithBlock:block]; + if ([self bugsnagStarted]) { + [self.notifier addBreadcrumbWithBlock:block]; + } } + (void)leaveBreadcrumbForNotificationName: (NSString *_Nonnull)notificationName { - [self.notifier crumbleNotification:notificationName]; + if ([self bugsnagStarted]) { + [self.notifier crumbleNotification:notificationName]; + } } + (void)setBreadcrumbCapacity:(NSUInteger)capacity { - self.notifier.configuration.breadcrumbs.capacity = capacity; + if ([self bugsnagStarted]) { + self.notifier.configuration.breadcrumbs.capacity = capacity; + } } + (void)clearBreadcrumbs { - [self.notifier clearBreadcrumbs]; + if ([self bugsnagStarted]) { + [self.notifier clearBreadcrumbs]; + } } + (void)startSession { - [self.notifier startSession]; + if ([self bugsnagStarted]) { + [self.notifier startSession]; + } } + (NSDateFormatter *)payloadDateFormatter { @@ -209,23 +237,31 @@ + (NSDateFormatter *)payloadDateFormatter { } + (void)setSuspendThreadsForUserReported:(BOOL)suspendThreadsForUserReported { - [[BSG_KSCrash sharedInstance] - setSuspendThreadsForUserReported:suspendThreadsForUserReported]; + if ([self bugsnagStarted]) { + [[BSG_KSCrash sharedInstance] + setSuspendThreadsForUserReported:suspendThreadsForUserReported]; + } } + (void)setReportWhenDebuggerIsAttached:(BOOL)reportWhenDebuggerIsAttached { - [[BSG_KSCrash sharedInstance] - setReportWhenDebuggerIsAttached:reportWhenDebuggerIsAttached]; + if ([self bugsnagStarted]) { + [[BSG_KSCrash sharedInstance] + setReportWhenDebuggerIsAttached:reportWhenDebuggerIsAttached]; + } } + (void)setThreadTracingEnabled:(BOOL)threadTracingEnabled { - [[BSG_KSCrash sharedInstance] setThreadTracingEnabled:threadTracingEnabled]; + if ([self bugsnagStarted]) { + [[BSG_KSCrash sharedInstance] setThreadTracingEnabled:threadTracingEnabled]; + } } + (void)setWriteBinaryImagesForUserReported: (BOOL)writeBinaryImagesForUserReported { - [[BSG_KSCrash sharedInstance] - setWriteBinaryImagesForUserReported:writeBinaryImagesForUserReported]; + if ([self bugsnagStarted]) { + [[BSG_KSCrash sharedInstance] + setWriteBinaryImagesForUserReported:writeBinaryImagesForUserReported]; + } } @end diff --git a/Source/BugsnagConfiguration.h b/Source/BugsnagConfiguration.h index 095281c5d..a2c18d5d4 100644 --- a/Source/BugsnagConfiguration.h +++ b/Source/BugsnagConfiguration.h @@ -193,4 +193,6 @@ BugsnagBreadcrumbs *breadcrumbs; @property(nullable) NSString *codeBundleId; @property(nullable) NSString *notifierType; +- (BOOL)hasValidApiKey; + @end diff --git a/Source/BugsnagConfiguration.m b/Source/BugsnagConfiguration.m index 1e78ac7d7..bcd9ce382 100644 --- a/Source/BugsnagConfiguration.m +++ b/Source/BugsnagConfiguration.m @@ -31,6 +31,7 @@ #import "BSG_RFC3339DateTool.h" #import "BugsnagUser.h" #import "BugsnagSessionTracker.h" +#import "BugsnagLogger.h" static NSString *const kHeaderApiPayloadVersion = @"Bugsnag-Payload-Version"; static NSString *const kHeaderApiKey = @"Bugsnag-Api-Key"; @@ -199,6 +200,22 @@ - (void)setAppVersion:(NSString *)newVersion { } } +@synthesize apiKey = _apiKey; + +- (NSString *)apiKey { + return _apiKey; +} + +- (void)setApiKey:(NSString *)apiKey { + if ([apiKey length] > 0) { + [self willChangeValueForKey:NSStringFromSelector(@selector(apiKey))]; + _apiKey = apiKey; + [self didChangeValueForKey:NSStringFromSelector(@selector(apiKey))]; + } else { + bsg_log_err(@"Attempted to override non-null API key with nil - ignoring."); + } +} + @synthesize shouldAutoCaptureSessions = _shouldAutoCaptureSessions; - (BOOL)shouldAutoCaptureSessions { @@ -231,4 +248,9 @@ - (NSDictionary *)sessionApiHeaders { kHeaderApiSentAt: [BSG_RFC3339DateTool stringFromDate:[NSDate new]] }; } + +- (BOOL)hasValidApiKey { + return [_apiKey length] > 0; +} + @end diff --git a/Source/BugsnagNotifier.h b/Source/BugsnagNotifier.h index cdf9a5d11..a4a9b6122 100644 --- a/Source/BugsnagNotifier.h +++ b/Source/BugsnagNotifier.h @@ -40,6 +40,7 @@ @property(nonatomic, readwrite, retain) NSLock *_Nonnull metaDataLock; @property(nonatomic) BSGConnectivity *_Nonnull networkReachable; +@property(readonly) BOOL started; - (instancetype _Nonnull)initWithConfiguration: (BugsnagConfiguration *_Nonnull)configuration; diff --git a/Source/BugsnagNotifier.m b/Source/BugsnagNotifier.m index 8687fb439..1eebb95d7 100644 --- a/Source/BugsnagNotifier.m +++ b/Source/BugsnagNotifier.m @@ -356,6 +356,7 @@ - (void)start { // notification not received in time on initial startup, so trigger manually [self willEnterForeground:self]; + _started = YES; } - (void)watchLifecycleEvents:(NSNotificationCenter *)center { diff --git a/Tests/BugsnagConfigurationTests.m b/Tests/BugsnagConfigurationTests.m index 3bc751783..373bffbf2 100644 --- a/Tests/BugsnagConfigurationTests.m +++ b/Tests/BugsnagConfigurationTests.m @@ -99,4 +99,31 @@ - (void)testUser { } +- (void)testApiKeySetter { + BugsnagConfiguration *config = [BugsnagConfiguration new]; + XCTAssertEqualObjects(@"", config.apiKey); + + config.apiKey = @"test"; + XCTAssertEqualObjects(@"test", config.apiKey); + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnonnull" + config.apiKey = nil; +#pragma clang diagnostic pop + + XCTAssertEqualObjects(@"test", config.apiKey); +} + +- (void)testHasValidApiKey { + BugsnagConfiguration *config = nil; + XCTAssertFalse([config hasValidApiKey]); + + config = [BugsnagConfiguration new]; + XCTAssertFalse([config hasValidApiKey]); + + config.apiKey = @"5adf89e0aaa"; + XCTAssertTrue([config hasValidApiKey]); +} + + @end