Skip to content

Commit

Permalink
feat: update ulysse
Browse files Browse the repository at this point in the history
  • Loading branch information
johackim committed Sep 12, 2024
1 parent 4569898 commit cfe984d
Show file tree
Hide file tree
Showing 24 changed files with 622 additions and 185 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Ulysse is a simple CLI tool for blocking your distracting apps and websites.
Prevent distractions by blocking your most distracting apps and websites, even if you are the administrator of your computer.

> [!WARNING]
> The shield mode block root access to your computer and can block you from disabling Ulysse.
> The shield mode block root access to your computer and can prevent you from disabling Ulysse.
>
> Make sure to remember your password.
>
Expand Down
47 changes: 24 additions & 23 deletions __tests__/block.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { config, editConfig, readConfig } from '../src/config';
import { DEFAULT_CONFIG } from '../src/constants';
import { disableShieldMode } from '../src/shield';
import { config, readConfig, resetConfig } from '../src/config';
import {
getBlockedApps,
blockDistraction,
Expand All @@ -11,13 +9,11 @@ import {
} from '../src/block';

beforeEach(async () => {
await disableShieldMode('ulysse');
await editConfig(DEFAULT_CONFIG);
Object.assign(config, DEFAULT_CONFIG);
await resetConfig();
jest.spyOn(console, 'log').mockImplementation(() => {});
});

test('Should check a distraction', async () => {
test('Should check if a distraction is valid', () => {
expect(isValidDistraction({ name: '' })).toBe(false);
expect(isValidDistraction({ name: '*' })).toBe(true);
expect(isValidDistraction({ name: '*.*' })).toBe(true);
Expand All @@ -33,13 +29,14 @@ test('Should block a distraction', async () => {
await blockDistraction({ name: 'example.com' });

expect(isDistractionBlocked('example.com')).toEqual(true);
expect(readConfig().blocklist).toContainEqual({ name: 'example.com', profile: 'default' });
});

test('Should block a distraction with a duration', async () => {
await blockDistraction({ name: 'twitter.com', time: '2m' });

expect(isDistractionBlocked('twitter.com')).toBe(true);
expect(config.blocklist).toEqual([{ name: 'twitter.com', time: '2m', timeout: expect.any(Number) }]);
expect(readConfig().blocklist).toContainEqual({ name: 'twitter.com', time: '2m', profile: 'default', timeout: expect.any(Number) });
});

test('Should block a distraction with a time-based interval', async () => {
Expand All @@ -49,13 +46,15 @@ test('Should block a distraction with a time-based interval', async () => {
await blockDistraction({ name: 'example.com', time: '0h-23h' });

expect(isDistractionBlocked('example.com')).toBe(true);
expect(readConfig().blocklist).toContainEqual({ name: 'example.com', profile: 'default', time: '0h-23h' });
});

test('Should block a specific subdomain', async () => {
await blockDistraction({ name: 'www.example.com' });

expect(isDistractionBlocked('www.example.com')).toBe(true);
expect(isDistractionBlocked('example.com')).toBe(false);
expect(readConfig().blocklist).toContainEqual({ name: 'www.example.com', profile: 'default' });
});

test('Should block all subdomains of a domain with a wildcard', async () => {
Expand Down Expand Up @@ -111,7 +110,7 @@ test('Should unblock a distraction', async () => {
expect(isDistractionBlocked('example.com')).toBe(false);
});

test('Should run isDistractionBlocked in less than 150ms with a large blocklist', async () => {
test.skip('Should run isDistractionBlocked in less than 150ms with a large blocklist', async () => {
config.blocklist = Array.from({ length: 500000 }, (_, i) => ({ name: `${i + 1}.com` }));

isDistractionBlocked('example.com');
Expand Down Expand Up @@ -147,10 +146,10 @@ test('Should get all blocked apps', async () => {
expect(blockedApps).toEqual(['node']);
});

test('Should get running blocked apps', () => {
test('Should get running blocked apps', async () => {
config.blocklist = [{ name: 'node' }, { name: 'firefox' }];

const runningBlockedApps = getRunningBlockedApps();
const runningBlockedApps = await getRunningBlockedApps();

expect(runningBlockedApps).toContainEqual({
name: 'node',
Expand All @@ -160,27 +159,21 @@ test('Should get running blocked apps', () => {
});
});

test('Should block all apps and websites', async () => {
test.skip('Should block all apps and websites', async () => {
await blockDistraction({ name: '*' });

const runningBlockedApps = await getRunningBlockedApps();

expect(isDistractionBlocked('example.com')).toEqual(true);
expect(isDistractionBlocked('node')).toEqual(true);
expect(getRunningBlockedApps()).toContainEqual({
name: 'node',
expect(isDistractionBlocked('chromium')).toEqual(true);
expect(runningBlockedApps).toContainEqual({
name: 'chromium',
pid: expect.any(Number),
cmd: expect.any(String),
bin: expect.any(String),
});
});

test('Should not block system process', async () => {
blockDistraction({ name: '*' });

const runningBlockedApps = JSON.stringify(getRunningBlockedApps());

expect(runningBlockedApps).not.toContain('/sbin/init');
});

test('Should not block all websites outside of a time range', async () => {
const currentDate = new Date('2021-01-01T12:00:00Z');
jest.spyOn(global, 'Date').mockImplementation(() => currentDate);
Expand All @@ -189,3 +182,11 @@ test('Should not block all websites outside of a time range', async () => {

expect(isDistractionBlocked('example.com')).toEqual(false);
});

test('Should not block a distraction from a profile disabled', async () => {
config.profiles = [{ name: 'default', enabled: false }];
await blockDistraction({ name: 'signal-desktop', profile: 'default' });

expect(isDistractionBlocked('signal-desktop')).toEqual(false);
expect(getBlockedApps()).not.toContain('signal-desktop');
});
6 changes: 2 additions & 4 deletions __tests__/commands.spec.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { config, editConfig } from '../src/config';
import { DEFAULT_CONFIG } from '../src/constants';
import { config, resetConfig } from '../src/config';
import { disableShieldMode } from '../src/shield';
import { helpCmd, versionCmd, blockCmd, whitelistCmd, unblockCmd, shieldCmd } from '../src/commands';

beforeEach(async () => {
process.argv = [];
await disableShieldMode('ulysse');
await editConfig(DEFAULT_CONFIG);
Object.assign(config, DEFAULT_CONFIG);
await resetConfig();
jest.spyOn(console, 'log').mockImplementation(() => {});
});

Expand Down
10 changes: 4 additions & 6 deletions __tests__/daemon.spec.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import fs from 'fs';
import { config, editConfig, readConfig } from '../src/config';
import { config, resetConfig, readConfig } from '../src/config';
import { getRunningApps } from '../src/utils';
import { blockDistraction } from '../src/block';
import { DEFAULT_CONFIG } from '../src/constants';
import { disableShieldMode } from '../src/shield';
import { handleAppBlocking, handleTimeout, updateResolvConf } from '../src/daemon';

Expand All @@ -18,15 +17,14 @@ jest.mock('child_process', () => ({

beforeEach(async () => {
await disableShieldMode('ulysse');
await editConfig(DEFAULT_CONFIG);
Object.assign(config, DEFAULT_CONFIG);
await resetConfig();
jest.spyOn(console, 'log').mockImplementation(() => {});
});

test('Should block a running app', async () => {
blockDistraction({ name: 'node' });
await blockDistraction({ name: 'node' });

handleAppBlocking();
await handleAppBlocking();

expect(console.log).toHaveBeenCalledWith('Blocking node');
});
Expand Down
15 changes: 15 additions & 0 deletions __tests__/profile.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { config, resetConfig } from '../src/config';
import { disableShieldMode } from '../src/shield';

beforeEach(async () => {
process.argv = [];
await disableShieldMode('ulysse');
await resetConfig();
jest.spyOn(console, 'log').mockImplementation(() => {});
});

test.skip('Should create a new profile', () => {
process.argv = ['ulysse', '-p', 'work'];

expect(config.profiles).toEqual([{ name: 'work', enabled: true }]);
});
13 changes: 6 additions & 7 deletions __tests__/shield.spec.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import { config, readConfig, editConfig } from '../src/config';
import { DEFAULT_CONFIG } from '../src/constants';
import { readConfig, resetConfig } from '../src/config';
import { whitelistDistraction } from '../src/whitelist';
import { enableShieldMode, disableShieldMode } from '../src/shield';
import { blockDistraction, unblockDistraction } from '../src/block';

beforeEach(async () => {
await disableShieldMode('ulysse');
await editConfig(DEFAULT_CONFIG);
Object.assign(config, DEFAULT_CONFIG);
await resetConfig();
jest.spyOn(console, 'log').mockImplementation(() => {});
});

Expand Down Expand Up @@ -42,13 +39,15 @@ test('Should not unblock a distraction if shield mode is enabled', async () => {

await unblockDistraction({ name: 'example.com' });

expect(readConfig().blocklist).toContainEqual({ name: 'example.com' });
const { blocklist } = readConfig();
expect(blocklist).toContainEqual({ name: 'example.com', profile: 'default' });
});

test('Should not whitelist a distraction if shield mode is enabled', async () => {
await enableShieldMode('ulysse');

await whitelistDistraction({ name: 'example.com' });

expect(readConfig().whitelist).not.toContainEqual({ name: 'example.com' });
const { whitelist } = readConfig();
expect(whitelist).not.toContainEqual({ name: 'example.com' });
});
16 changes: 4 additions & 12 deletions __tests__/whitelist.spec.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { config, readConfig, editConfig } from '../src/config';
import { DEFAULT_CONFIG } from '../src/constants';
import { config, resetConfig } from '../src/config';
import { disableShieldMode } from '../src/shield';
import { blockDistraction, isDistractionBlocked, getRunningBlockedApps } from '../src/block';
import { isDistractionWhitelisted, whitelistDistraction } from '../src/whitelist';
import { whitelistDistraction } from '../src/whitelist';

jest.mock('../src/utils', () => ({
...jest.requireActual('../src/utils'),
Expand All @@ -15,8 +14,7 @@ jest.mock('../src/utils', () => ({

beforeEach(async () => {
await disableShieldMode('ulysse');
await editConfig(DEFAULT_CONFIG);
Object.assign(config, DEFAULT_CONFIG);
await resetConfig();
jest.spyOn(console, 'log').mockImplementation(() => {});
});

Expand All @@ -25,7 +23,7 @@ test('Should whitelist a distraction', async () => {

await whitelistDistraction(distraction);

expect(readConfig().whitelist).toEqual([distraction]);
expect(config.whitelist).toEqual([distraction]);
});

test('Should not block a domain if it is in the whitelist', async () => {
Expand All @@ -42,12 +40,6 @@ test('Should not block a domain if it is in the whitelist with a wildcard', asyn
expect(isDistractionBlocked('www.example.com')).toBe(false);
});

test('Should not block a process from the system whitelist', async () => {
await blockDistraction({ name: '*' });

expect(isDistractionWhitelisted('systemd')).toBe(true);
});

test('Should not whitelist a blocked process outside of a time range', async () => {
const currentDate = new Date('2021-01-01T12:00:00Z');
jest.spyOn(global, 'Date').mockImplementation(() => currentDate);
Expand Down
9 changes: 9 additions & 0 deletions __tests__/x11.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { listActiveWindows } from '../src/x11';

test.skip('Should list active windows', async () => {
const windows = await listActiveWindows();

expect(windows[0]).toEqual(
{ windowId: expect.any(Number), name: expect.any(String), pid: expect.any(Number) },
);
});
14 changes: 14 additions & 0 deletions customSequencer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/* eslint class-methods-use-this: 0 */
const TestSequencer = require('@jest/test-sequencer').default;

class AlphabeticalSequencer extends TestSequencer {
sort(tests) {
return tests.sort((testA, testB) => {
const nameA = testA.path.toUpperCase();
const nameB = testB.path.toUpperCase();
return nameA.localeCompare(nameB);
});
}
}

module.exports = AlphabeticalSequencer;
33 changes: 14 additions & 19 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,45 +33,40 @@
],
"dependencies": {
"dns-packet": "^5.6.1",
"gun": "^0.2020.1240"
"enquirer": "^2.4.1",
"gun": "^0.2020.1240",
"x11": "^2.3.0"
},
"devDependencies": {
"@babel/cli": "^7.23.9",
"@babel/core": "^7.23.9",
"@babel/node": "^7.23.9",
"@babel/preset-env": "^7.23.9",
"@babel/cli": "^7.24.8",
"@babel/core": "^7.24.9",
"@babel/node": "^7.24.8",
"@babel/preset-env": "^7.24.8",
"@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-commonjs": "^26.0.1",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-terser": "^0.4.4",
"babel-plugin-transform-remove-strict-mode": "^0.0.2",
"dotenv": "^16.4.5",
"eslint": "^8.57.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jest": "^27.9.0",
"eslint-plugin-jest": "^28.6.0",
"jest": "^29.7.0",
"rollup": "^4.12.0"
"rollup": "^4.18.1"
},
"scripts": {
"lint": "eslint src",
"prepublishOnly": "npm run build",
"prebuild": "rm -rf dist",
"build": "rollup --bundleConfigAsCjs -c",
"build": "rollup --bundleConfigAsCjs --no-strict -c",
"start": "babel-node src/index.js",
"test": "DOTENV_CONFIG_PATH=.env.test jest -i --setupFiles dotenv/config --forceExit"
},
"jest": {
"testSequencer": "./customSequencer.js",
"globalSetup": "./jest.setup.js",
"restoreMocks": true,
"transformIgnorePatterns": [],
"transform": {
"\\.js$": [
"babel-jest",
{
"configFile": "./babel.config.js"
}
]
}
"restoreMocks": true
}
}
6 changes: 5 additions & 1 deletion rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ export default {
plugins: [
json(),
terser(),
commonjs(),
commonjs({
dynamicRequireTargets: [
'node_modules/x11/lib/ext/big-requests.js',
],
}),
nodeResolve(),
babel({ babelHelpers: 'bundled' }),
],
Expand Down
Loading

0 comments on commit cfe984d

Please sign in to comment.