Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
2d44619
added new code for network extension and safari/chrome ext
satendradagar Oct 28, 2025
9fe1046
implemented extension with blocker customization
satendradagar Nov 29, 2025
e4198c7
implemented web extension, fixed existing project
satendradagar Dec 29, 2025
bb56c78
added legacy tool files
satendradagar Jan 14, 2026
4b19eb3
added app delegate to handle different app states
satendradagar Jan 14, 2026
a67a343
add tool in the info plist configuration
satendradagar Jan 14, 2026
52672b0
integrated app delegate adaptop
satendradagar Jan 14, 2026
60792da
passed setting to activate tool
satendradagar Jan 14, 2026
0594ffe
added new files in the project
satendradagar Jan 14, 2026
c6ecdc9
activate /deactivate legacy blocking conditionally
satendradagar Jan 14, 2026
e3abb7f
updated messages and file constant
satendradagar Jan 14, 2026
b247dcb
added daemon helper file
satendradagar Jan 14, 2026
8b065e0
updated filter data logic
satendradagar Jan 14, 2026
d8e3420
integrated New UI flow
satendradagar Jan 30, 2026
9d0f2d6
added new ui
satendradagar Jan 30, 2026
5c7ffbd
added new icons in the app
satendradagar Feb 22, 2026
8232372
updated version number
satendradagar Feb 22, 2026
b9212a0
added onboarding steps and import export manager
satendradagar Feb 22, 2026
75e44e1
updated main app view
satendradagar Feb 22, 2026
46cd683
integrated extension state handler to update the ui
satendradagar Feb 22, 2026
5dd76f2
updated view to test onboarding view
satendradagar Feb 22, 2026
7654a76
added state handing with rew ui and udpated actions
satendradagar Feb 22, 2026
0bbb4f8
added new keys in preferences to save ext state
satendradagar Feb 23, 2026
0a04b1c
added callbacks in safari extension
satendradagar Feb 23, 2026
7136e2a
added icon and gesture in the ui
satendradagar Feb 23, 2026
24bd641
changed message of block list
satendradagar Feb 23, 2026
ca88f67
integrated import and export functionality
satendradagar Feb 23, 2026
b0e05fd
Implemented event scheduler and runner
satendradagar Mar 1, 2026
0e5d237
updated view and model to handle schedule time
satendradagar Mar 1, 2026
9e3e767
updated chrome script for more better handlings
satendradagar Apr 6, 2026
a412173
added new persmissions
satendradagar Apr 6, 2026
7f952da
log and signing fixed
satendradagar Apr 6, 2026
2197318
updated app version in return call
satendradagar Apr 6, 2026
2fa274a
implemented notification and sounds alerts
satendradagar Apr 7, 2026
6cf8198
Fixed issues
satendradagar Apr 7, 2026
d4e42a4
fixed UI issus
satendradagar Apr 7, 2026
efe339c
Fixed issue and preferences
satendradagar Apr 7, 2026
520c2ad
cleanup and fixed some issues
satendradagar Apr 7, 2026
96e2895
fixed filter isues
satendradagar Apr 7, 2026
0b05383
Implemented notifications, sound , dock and schedule view handlings f…
satendradagar Apr 30, 2026
bd9c994
restructure code to make it more modular
satendradagar May 1, 2026
06dcbc7
updated file paths and implemented backed service to support function…
satendradagar May 18, 2026
42ea465
relocated files to right folder
satendradagar May 18, 2026
e34d5ef
Implemented Chrome extension handling with new background blocking fe…
satendradagar May 22, 2026
198614d
Timer handlings and other basic handlings for Safari extension
satendradagar May 24, 2026
09f3896
commented out filter view model code to handle extension state and se…
satendradagar May 24, 2026
fbf9092
commented public key
satendradagar May 24, 2026
e3e82db
partial code in script for safari
satendradagar May 24, 2026
c060fc5
fixed issues
satendradagar May 27, 2026
7f64862
Fixed issues and code migration
satendradagar Jun 2, 2026
4e27c0e
fixed extension install update issue
satendradagar Jun 3, 2026
cc37400
code cleanup, removed unused code
satendradagar Jun 3, 2026
e6fadb7
removed un necessary code for protocol confirmation
satendradagar Jun 4, 2026
14a6788
Fixed issues, updated logging, other issues debugging
satendradagar Jun 14, 2026
81a407e
reverted file and relocated
satendradagar Jun 14, 2026
a50e412
updated version number
satendradagar Jun 20, 2026
e893ace
shifted okay button in case of check internet connection state
satendradagar Jun 20, 2026
287581a
added advance logging
satendradagar Jun 20, 2026
3bb9b21
updated logging
satendradagar Jun 20, 2026
66db2a8
updated logging to write in files
satendradagar Jun 20, 2026
22dd6f9
updated logic to handle the connection request on queue and updated l…
satendradagar Jun 20, 2026
b8cf9be
removed unused code, code cleanup and other logic fixed and changed
satendradagar Jun 22, 2026
c2ca565
implemented services and code cleanup
satendradagar Jun 26, 2026
9e35d34
added files for Chrome extension
satendradagar Jun 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions AppController.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
#import "SCXPCClient.h"
#import "SCBlockFileReaderWriter.h"
#import "SCUIUtilities.h"
#import <TransformerKit/NSValueTransformer+TransformerKit.h>

@interface AppController () {}

Expand Down Expand Up @@ -608,23 +607,23 @@ - (void)installBlock {
// we're about to launch a helper tool which will read settings, so make sure the ones on disk are valid
[self->settings_ synchronizeSettings];
[self->defaults_ synchronize];

NSDictionary *blockSettings = @{
@"ClearCaches": [self->defaults_ valueForKey: @"ClearCaches"],
@"AllowLocalNetworks": [self->defaults_ valueForKey: @"AllowLocalNetworks"],
@"EvaluateCommonSubdomains": [self->defaults_ valueForKey: @"EvaluateCommonSubdomains"],
@"IncludeLinkedDomains": [self->defaults_ valueForKey: @"IncludeLinkedDomains"],
@"BlockSoundShouldPlay": [self->defaults_ valueForKey: @"BlockSoundShouldPlay"],
@"BlockSound": [self->defaults_ valueForKey: @"BlockSound"],
@"EnableErrorReporting": [self->defaults_ valueForKey: @"EnableErrorReporting"]
};
// ok, the new helper tool is installed! refresh the connection, then it's time to start the block
[self.xpc refreshConnectionAndRun:^{
NSLog(@"Refreshed connection and ready to start block!");
[self.xpc startBlockWithControllingUID: getuid()
blocklist: [self->defaults_ arrayForKey: @"Blocklist"]
isAllowlist: [self->defaults_ boolForKey: @"BlockAsWhitelist"]
endDate: newBlockEndDate
blockSettings: @{
@"ClearCaches": [self->defaults_ valueForKey: @"ClearCaches"],
@"AllowLocalNetworks": [self->defaults_ valueForKey: @"AllowLocalNetworks"],
@"EvaluateCommonSubdomains": [self->defaults_ valueForKey: @"EvaluateCommonSubdomains"],
@"IncludeLinkedDomains": [self->defaults_ valueForKey: @"IncludeLinkedDomains"],
@"BlockSoundShouldPlay": [self->defaults_ valueForKey: @"BlockSoundShouldPlay"],
@"BlockSound": [self->defaults_ valueForKey: @"BlockSound"],
@"EnableErrorReporting": [self->defaults_ valueForKey: @"EnableErrorReporting"]
}
blockSettings: blockSettings
reply:^(NSError * _Nonnull error) {
if (error != nil) {
[SCUIUtilities presentError: error];
Expand Down
2 changes: 1 addition & 1 deletion ButtonWithPopupMenu.m
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,4 @@ - (void)dealloc {
}


@end
@end
67 changes: 34 additions & 33 deletions Common/SCSentry.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,33 @@
#import "SCSettings.h"

#ifndef TESTING
#import <Sentry/Sentry.h>
//#import <Sentry/Sentry.h>
//#import <Sentry/Sentry.h>
#endif

@implementation SCSentry

//org.eyebeam.SelfControl
+ (void)startSentry:(NSString*)componentId {
#ifndef TESTING
[SentrySDK startWithConfigureOptions:^(SentryOptions *options) {
options.dsn = @"https://58fbe7145368418998067f88896007b2@o504820.ingest.sentry.io/5592195";
options.releaseName = [NSString stringWithFormat: @"%@%@", componentId, SELFCONTROL_VERSION_STRING];
options.enableAutoSessionTracking = NO;
options.environment = @"dev";

// make sure no data leaves the device if error reporting isn't enabled
options.beforeSend = ^SentryEvent * _Nullable(SentryEvent * _Nonnull event) {
if ([SCSentry errorReportingEnabled]) {
return event;
} else {
return NULL;
}
};
}];
[SentrySDK configureScope:^(SentryScope * _Nonnull scope) {
[scope setTagValue: [[NSLocale currentLocale] localeIdentifier] forKey: @"localeId"];
}];
// [SentrySDK startWithConfigureOptions:^(SentryOptions *options) {
// options.dsn = @"https://58fbe7145368418998067f88896007b2@o504820.ingest.sentry.io/5592195";
// options.releaseName = [NSString stringWithFormat: @"%@%@", componentId, SELFCONTROL_VERSION_STRING];
// options.enableAutoSessionTracking = NO;
// options.environment = @"dev";
//
// // make sure no data leaves the device if error reporting isn't enabled
// options.beforeSend = ^SentryEvent * _Nullable(SentryEvent * _Nonnull event) {
// if ([SCSentry errorReportingEnabled]) {
// return event;
// } else {
// return NULL;
// }
// };
// }];
// [SentrySDK configureScope:^(SentryScope * _Nonnull scope) {
// [scope setTagValue: [[NSLocale currentLocale] localeIdentifier] forKey: @"localeId"];
// }];
#endif
}

Expand Down Expand Up @@ -113,19 +114,19 @@ + (void)updateDefaultsContext {
[defaultsDict removeObjectForKey: @"SULastProfileSubmissionDate"];

#ifndef TESTING
[SentrySDK configureScope:^(SentryScope * _Nonnull scope) {
[scope setContextValue: defaultsDict forKey: @"NSUserDefaults"];
}];
// [SentrySDK configureScope:^(SentryScope * _Nonnull scope) {
// [scope setContextValue: defaultsDict forKey: @"NSUserDefaults"];
// }];
#endif
}

+ (void)addBreadcrumb:(NSString*)message category:(NSString*)category {
#ifndef TESTING
SentryBreadcrumb* crumb = [[SentryBreadcrumb alloc] init];
crumb.level = kSentryLevelInfo;
crumb.category = category;
crumb.message = message;
[SentrySDK addBreadcrumb: crumb];
// SentryBreadcrumb* crumb = [[SentryBreadcrumb alloc] init];
// crumb.level = kSentryLevelInfo;
// crumb.category = category;
// crumb.message = message;
// [SentrySDK addBreadcrumb: crumb];
#endif
}

Expand All @@ -147,7 +148,7 @@ + (void)captureError:(NSError*)error {
[[SCSettings sharedSettings] updateSentryContext];
[SCSentry updateDefaultsContext];
#ifndef TESTING
[SentrySDK captureError: error];
// [SentrySDK captureError: error];
#endif
}

Expand All @@ -170,11 +171,11 @@ + (void)captureMessage:(NSString*)message withScopeBlock:(nullable void (^)(Sent
[SCSentry updateDefaultsContext];

#ifndef TESTING
if (block != nil) {
[SentrySDK captureMessage: message withScopeBlock: block];
} else {
[SentrySDK captureMessage: message];
}
// if (block != nil) {
// [SentrySDK captureMessage: message withScopeBlock: block];
// } else {
// [SentrySDK captureMessage: message];
// }
#endif
}

Expand Down
8 changes: 4 additions & 4 deletions Common/SCSettings.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#import <AppKit/AppKit.h>

#ifndef TESTING
#import <Sentry/Sentry.h>
//#import <Sentry/Sentry.h>
#endif

float const SYNC_INTERVAL_SECS = 30;
Expand Down Expand Up @@ -485,9 +485,9 @@ - (void)updateSentryContext {
}

#ifndef TESTING
[SentrySDK configureScope:^(SentryScope * _Nonnull scope) {
[scope setContextValue: dictCopy forKey: @"SCSettings"];
}];
// [SentrySDK configureScope:^(SentryScope * _Nonnull scope) {
// [scope setContextValue: dictCopy forKey: @"SCSettings"];
// }];
#endif
}

Expand Down
9 changes: 8 additions & 1 deletion Daemon/SCDaemon.m
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ - (void)startInactivityTimer {
}
}];
}

- (void)resetInactivityTimer {
self.lastActivityDate = [NSDate date];
}
Expand All @@ -146,6 +147,11 @@ - (void)dealloc {
#pragma mark - NSXPCListenerDelegate

- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
//#if DEBUG
// // In Debug builds, skip code signature validation to ease development.
// NSLog(@"[DEBUG] Accepting XPC connection without signature validation.");
// [SCSentry addBreadcrumb:@"DEBUG: accepted XPC connection without validation" category:@"daemon"];
//#else
// There is a potential security issue / race condition with matching based on PID, so we use the (technically private) auditToken instead
audit_token_t auditToken = newConnection.auditToken;
NSDictionary* guestAttributes = @{
Expand All @@ -159,7 +165,7 @@ - (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConne
SecRequirementRef isSelfControlApp;
// versions before 4.0 didn't have hardened code signing, so aren't trustworthy to talk to the daemon
// (plus the daemon didn't exist before 4.0 so there's really no reason they should want to run it!)
SecRequirementCreateWithString(CFSTR("anchor apple generic and (identifier \"org.eyebeam.SelfControl\" or identifier \"org.eyebeam.selfcontrol-cli\") and info [CFBundleVersion] >= \"407\" and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = EG6ZYP3AQH)"), kSecCSDefaultFlags, &isSelfControlApp);
SecRequirementCreateWithString(CFSTR("anchor apple generic and (identifier \"org.eyebeam.SelfControl\" or identifier \"org.eyebeam.selfcontrol-cli\") and info [CFBundleVersion] >= \"407\""), kSecCSDefaultFlags, &isSelfControlApp);
OSStatus clientValidityStatus = SecCodeCheckValidity(guest, kSecCSDefaultFlags, isSelfControlApp);

CFRelease(guest);
Expand All @@ -171,6 +177,7 @@ - (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConne
[SCSentry captureError: error];
return NO;
}
//#endif

SCDaemonXPC* scdXPC = [[SCDaemonXPC alloc] init];
newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol: @protocol(SCDaemonProtocol)];
Expand Down
2 changes: 1 addition & 1 deletion Daemon/SCDaemonXPC.m
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ - (void)getVersionWithReply:(void(^)(NSString * version))reply {
NSLog(@"XPC method called: getVersionWithReply");
// We specifically don't check for authorization here. Everyone is always allowed to get
// the version of the helper tool.
reply(SELFCONTROL_VERSION_STRING);
reply(@"4.0.2");
}

@end
2 changes: 1 addition & 1 deletion Daemon/selfcontrold-Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
<string>Free and open-source under the GPL.</string>
<key>SMAuthorizedClients</key>
<array>
<string>anchor apple generic and (identifier &quot;org.eyebeam.SelfControl&quot; or identifier &quot;org.eyebeam.selfcontrol-cli&quot;) and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = EG6ZYP3AQH)</string>
<string>anchor apple generic and (identifier &quot;org.eyebeam.SelfControl&quot; or identifier &quot;org.eyebeam.selfcontrol-cli&quot;)</string>
</array>
</dict>
</plist>
6 changes: 3 additions & 3 deletions Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,18 @@
<key>SMPrivilegedExecutables</key>
<dict>
<key>org.eyebeam.selfcontrold</key>
<string>anchor apple generic and identifier &quot;org.eyebeam.selfcontrold&quot; and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = EG6ZYP3AQH)</string>
<string>anchor apple generic and identifier "org.eyebeam.selfcontrold"</string>
</dict>
<key>SUEnableAutomaticChecks</key>
<true/>
<key>SUEnableJavaScript</key>
<true/>
<key>SUEnableSystemProfiling</key>
<true/>
<key>SUFeedURL</key>
<string>https://selfcontrolapp.com/appcast.xml</string>
<key>SUPublicDSAKeyFile</key>
<string>dsa_pub.pem</string>
<key>SUEnableSystemProfiling</key>
<true/>
<key>SUSendProfileInfo</key>
<true/>
</dict>
Expand Down
9 changes: 2 additions & 7 deletions Podfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
source 'https://github.com/CocoaPods/Specs.git'

minVersion = '10.10'
minVersion = '11.5'

platform :osx, minVersion

Expand All @@ -11,10 +11,9 @@ plugin 'cocoapods-prune-localizations', { :localizations => supported_locales }
target "SelfControl" do
use_frameworks! :linkage => :static
pod 'MASPreferences', '~> 1.1.4'
pod 'TransformerKit', '~> 1.1.1'
pod 'FormatterKit/TimeIntervalFormatter', '~> 1.8.0'
pod 'LetsMove', '~> 1.24'
pod 'Sentry', :git => 'https://github.com/getsentry/sentry-cocoa.git', :tag => '7.3.0'
pod 'Sentry'

# Add test target
target 'SelfControlTests' do
Expand All @@ -24,19 +23,15 @@ end

target "SelfControl Killer" do
use_frameworks! :linkage => :static
pod 'Sentry', :git => 'https://github.com/getsentry/sentry-cocoa.git', :tag => '7.3.0'
end

# we can't use_frameworks on these because they're command-line tools
# Sentry says we need use_frameworks, but they seem to work OK anyway?
target "SCKillerHelper" do
pod 'Sentry', :git => 'https://github.com/getsentry/sentry-cocoa.git', :tag => '7.3.0'
end
target "selfcontrol-cli" do
pod 'Sentry', :git => 'https://github.com/getsentry/sentry-cocoa.git', :tag => '7.3.0'
end
target "org.eyebeam.selfcontrold" do
pod 'Sentry', :git => 'https://github.com/getsentry/sentry-cocoa.git', :tag => '7.3.0'
end

post_install do |pi|
Expand Down
35 changes: 18 additions & 17 deletions SCDurationSlider.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

#import "SCDurationSlider.h"
#import "SCTimeIntervalFormatter.h"
#import <TransformerKit/NSValueTransformer+TransformerKit.h>

#define kValueTransformerName @"BlockDurationSliderTransformer"

Expand Down Expand Up @@ -47,29 +46,31 @@ - (void)setMaxDuration:(NSInteger)maxDuration {
}

- (void)registerMinutesValueTransformer {
[NSValueTransformer registerValueTransformerWithName: kValueTransformerName
transformedValueClass: [NSNumber class]
returningTransformedValueWithBlock:^id _Nonnull(id _Nonnull value) {
// if it's not a number or convertable to one, IDK man
if (![value respondsToSelector: @selector(floatValue)]) return @0;

long minutesValue = lroundf([value floatValue]);
return @(minutesValue);
}];

//SS: TODO:
// [NSValueTransformer registerValueTransformerWithName: kValueTransformerName
// transformedValueClass: [NSNumber class]
// returningTransformedValueWithBlock:^id _Nonnull(id _Nonnull value) {
// // if it's not a number or convertable to one, IDK man
// if (![value respondsToSelector: @selector(floatValue)]) return @0;
//
// long minutesValue = lroundf([value floatValue]);
// return @(minutesValue);
// }];
}

- (NSInteger)durationValueMinutes {
return lroundf(self.floatValue);
}

- (void)bindDurationToObject:(id)obj keyPath:(NSString*)keyPath {
[self bind: @"value"
toObject: obj
withKeyPath: keyPath
options: @{
NSContinuouslyUpdatesValueBindingOption: @YES,
NSValueTransformerNameBindingOption: kValueTransformerName
}];
// [self bind: @"value"
// toObject: obj
// withKeyPath: keyPath
// options: @{
// NSContinuouslyUpdatesValueBindingOption: @YES,
// NSValueTransformerNameBindingOption: kValueTransformerName
// }];
}

- (NSString*)durationDescription {
Expand Down
Binary file added Self-Control-Extension/SelfControl-Blocker.zip
Binary file not shown.
Loading