Compare commits

..

28 Commits
0.7.0 ... 0.7.4

Author SHA1 Message Date
undergroundwires
ee66196d9a fix wrong path in clear all firefox user profile settings 2020-09-14 16:04:38 +01:00
undergroundwires
3c13a9e837 fix missing reg value in denying app access to account 2020-09-14 16:03:03 +01:00
undergroundwires
22b23a9ece fix spectre protection getting single lined #31 2020-09-14 16:00:20 +01:00
undergroundwires
4ae385b7fc fix checked checkbox has blue border 2020-09-13 18:42:19 +01:00
undergroundwires-bot
d9abc7f0b2 ⬆️ bumped to 0.7.3 2020-09-12 13:14:13 +00:00
undergroundwires
1f19b2528a fix typo in a test 2020-09-12 14:42:27 +01:00
undergroundwires
1f11c39773 add more detailed error message 2020-09-12 00:14:27 +01:00
undergroundwires
b6ccb5927a fix comment lines are being detected as duplicate in validation 2020-09-12 00:13:58 +01:00
undergroundwires
1d465ee318 add reversibility and more scripts to denying app access with better structure 2020-09-12 00:11:10 +01:00
undergroundwires
3ab48b1cf5 fix naming of firefox cleanup to mention profiles 2020-09-11 14:26:32 +01:00
undergroundwires
de4ac978bd fix wrong path to the main telemetry file 2020-09-10 12:52:29 +01:00
undergroundwires
8df5faf4ef improve CPU specific tweaks by conditional platform checks and reversibility 2020-09-09 13:55:21 +01:00
undergroundwires
99a2035fdb fix nvidia tweak error message, categorize and add reversibility 2020-09-08 19:41:03 +01:00
undergroundwires
a0d61728ea fix vscode settings file override and add more configs 2020-09-07 13:42:59 +01:00
undergroundwires-bot
312bf6102c ⬆️ bumped to 0.7.2 2020-09-06 18:10:12 +00:00
undergroundwires
f4885b6f1c add best practice suggestion to come back 2020-09-06 02:41:11 +01:00
undergroundwires
ca63a0979e fix wording in default text in text area 2020-09-06 02:37:47 +01:00
undergroundwires
1f266c3353 fix indeterminate state being lost 2020-09-06 15:26:19 +01:00
undergroundwires
c7b2a70312 add reversibility to removing bloatware 2020-09-06 19:03:36 +01:00
undergroundwires
255133af4d fix bad highlighting of selected nodes when using keyboard navigation 2020-09-04 01:24:35 +01:00
undergroundwires
db74531cd4 add reversibility for biometric disabling and do not recommend it 2020-09-06 16:39:48 +01:00
undergroundwires
f36d8bfc78 update onesync documentation and do not recommend it as it breaks other apps 2020-09-05 23:31:31 +01:00
undergroundwires-bot
3b31ace726 ⬆️ bumped to 0.7.1 2020-09-04 11:42:03 +00:00
undergroundwires
6badfef9da refactor unused imports 2020-09-04 13:29:42 +01:00
undergroundwires
8c38dd73d8 fix new/changed script higlighting not working on production builds 2020-09-04 13:26:35 +01:00
undergroundwires
b8682a852a rename screenshot image file 2020-09-04 13:25:36 +01:00
undergroundwires
8c17929151 fix some browsers (including firefox) downloading the script as a text file 2020-09-04 12:20:41 +01:00
undergroundwires-bot
bb92c9ec28 ⬆️ bumped to 0.7.0 2020-09-02 21:26:40 +00:00
20 changed files with 1087 additions and 397 deletions

View File

@@ -1,5 +1,67 @@
# Changelog # Changelog
## 0.7.3 (2020-09-12)
* fix vscode settings file override and add more configs | [commit](https://github.com/undergroundwires/privacy.sexy/commit/a0d61728ead04b4455437f85820121a848db9e00)
* fix nvidia tweak error message, categorize and add reversibility | [commit](https://github.com/undergroundwires/privacy.sexy/commit/99a2035fdb0766a4dfc2753133eab0d7666516cd)
* improve CPU specific tweaks by conditional platform checks and reversibility | [commit](https://github.com/undergroundwires/privacy.sexy/commit/8df5faf4ef05a49da63973bd0fbb5c5d07d5bd93)
* fix wrong path to the main telemetry file | [commit](https://github.com/undergroundwires/privacy.sexy/commit/de4ac978bdda79573b36d355697b8a028d2c0beb)
* fix naming of firefox cleanup to mention profiles | [commit](https://github.com/undergroundwires/privacy.sexy/commit/3ab48b1cf5f7f934f07e468ef2318ccee07f530c)
* add reversibility and more scripts to denying app access with better structure | [commit](https://github.com/undergroundwires/privacy.sexy/commit/1d465ee3189d0e5a827453b3f0eb4361efe23770)
* fix comment lines are being detected as duplicate in validation | [commit](https://github.com/undergroundwires/privacy.sexy/commit/b6ccb5927a20412976a54fd2215eb645092f98a8)
* add more detailed error message | [commit](https://github.com/undergroundwires/privacy.sexy/commit/1f11c39773c12eccfb3efb898b58c2f6f37ab9ca)
* fix typo in a test | [commit](https://github.com/undergroundwires/privacy.sexy/commit/1f19b2528a69383e63e579d2885f01cd804abf6c)
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.7.2...0.7.3)
## 0.7.2 (2020-09-06)
* update onesync documentation and do not recommend it as it breaks other apps | [commit](https://github.com/undergroundwires/privacy.sexy/commit/f36d8bfc7848bb65ac0c641e318a689bf3816ccf)
* add reversibility for biometric disabling and do not recommend it | [commit](https://github.com/undergroundwires/privacy.sexy/commit/db74531cd4139615c6d595959217d3651f099019)
* fix bad highlighting of selected nodes when using keyboard navigation | [commit](https://github.com/undergroundwires/privacy.sexy/commit/255133af4dfae40171406648a3e2920f16d71cb3)
* add reversibility to removing bloatware | [commit](https://github.com/undergroundwires/privacy.sexy/commit/c7b2a703128470a05f12c9c6e8002444def37ef8)
* fix indeterminate state being lost | [commit](https://github.com/undergroundwires/privacy.sexy/commit/1f266c33535f72b69c65985bf2eff27cd2c5a104)
* fix wording in default text in text area | [commit](https://github.com/undergroundwires/privacy.sexy/commit/ca63a0979ef55d07d09d9443e5cea9aa888870a5)
* add best practice suggestion to come back | [commit](https://github.com/undergroundwires/privacy.sexy/commit/f4885b6f1c82752f2143934e336d6d1b1af03015)
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.7.1...0.7.2)
## 0.7.1 (2020-09-04)
* fix some browsers (including firefox) downloading the script as a text file | [commit](https://github.com/undergroundwires/privacy.sexy/commit/8c17929151f9c4fa5f48564492bbf400ced95eea)
* rename screenshot image file | [commit](https://github.com/undergroundwires/privacy.sexy/commit/b8682a852a14ed6cf49986695d9510b840ac9d3d)
* fix new/changed script higlighting not working on production builds | [commit](https://github.com/undergroundwires/privacy.sexy/commit/8c38dd73d8c7b77d8d341c0389f4d7229f9b97fd)
* refactor unused imports | [commit](https://github.com/undergroundwires/privacy.sexy/commit/6badfef9daace0c5de3fd33652a82bfe22261b11)
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.7.0...0.7.1)
## 0.7.0 (2020-09-02)
* [search] better (multilined) message when there are no results | [commit](https://github.com/undergroundwires/privacy.sexy/commit/ec15af01dd020b364c2174fe562fd66227c2320c)
* [search] added clear/close button | [commit](https://github.com/undergroundwires/privacy.sexy/commit/d6fa9a2a03c0ebe68b94f0b80cc52b4e200c9213)
* move script generation to /generation | [commit](https://github.com/undergroundwires/privacy.sexy/commit/5df458739d076719e350ba194c4f3f772884fcdb)
* add auto-highlighting of selected/updated code | [commit](https://github.com/undergroundwires/privacy.sexy/commit/b789250cb89e2130b08e1a927df8181cf945dfeb)
* prompt admin priviliges automatically | [commit](https://github.com/undergroundwires/privacy.sexy/commit/f8ba5c46e4923d9c35f200f8a08aa6437f7c0ecc)
* add removal of ghost (default0) telemetry user | [commit](https://github.com/undergroundwires/privacy.sexy/commit/c262681011f39b4412669b6cf233476f676ca550)
* add more windows defender tweaks, categorization and reversibility | [commit](https://github.com/undergroundwires/privacy.sexy/commit/1a34c7374ba56bafa0209bbb55c81b233bb419ed)
* fix NTP script documentation is on wrong place | [commit](https://github.com/undergroundwires/privacy.sexy/commit/3060ebf79cf242370433495cc3e1878b7581b202)
* updated dependencies to latest and audit fixes (#25) | [commit](https://github.com/undergroundwires/privacy.sexy/commit/c628aa9aef8ab7c815661d3c1711e7fbc65c69a2)
* categorize, fix and extend windows log files cleanup | [commit](https://github.com/undergroundwires/privacy.sexy/commit/594a14d6ca76cbd27a21877b8c373c1930589ca6)
* add more OneDrive cleanup scripts and categorize them | [commit](https://github.com/undergroundwires/privacy.sexy/commit/978d7d08638dd161082f239ed088b12302f29458)
* add disabling firefox telemetry | [commit](https://github.com/undergroundwires/privacy.sexy/commit/f8b8b4c97ab734d5ba7370894b694993924388da)
* add disabling ccleaner telemetry | [commit](https://github.com/undergroundwires/privacy.sexy/commit/018b7e270f207aac926cb12f8069ebfcdce193ce)
* Add disabling of PowerShell 7+ telemetry (#29) | [commit](https://github.com/undergroundwires/privacy.sexy/commit/456e40bedf9afcc846f9b13f1ea144cef6115cf6)
* categorize, fix, make scripts reversible in "UI for privacy", "security improvements" and "configure browsers" | [commit](https://github.com/undergroundwires/privacy.sexy/commit/532915b95da9fecd6b981d91bf489359e4e53caa)
* fix "Configure Defender" being in wrong category #28 | [commit](https://github.com/undergroundwires/privacy.sexy/commit/f709d6a566ed7846b677b383863deda9680a2a9c)
* do not hardcode capability versions and make them reversible | [commit](https://github.com/undergroundwires/privacy.sexy/commit/2afef4ea3d0d3d09aa1fa1eedba8493680bd8f10)
* exclude paint, wordpad and notepad from bloatware removal | [commit](https://github.com/undergroundwires/privacy.sexy/commit/d235dee95514a01745aef9479d07f88ffb4b40b8)
* add reversibility on category level | [commit](https://github.com/undergroundwires/privacy.sexy/commit/f51e8859eeb32c944126d692cfe03a0320c8b568)
* refactor unused imports & variables | [commit](https://github.com/undergroundwires/privacy.sexy/commit/a23d28f2cfa2d64d45460697cf5ee9d6b5920752)
* fix search (got broken in b789250) with tests and refactorings | [commit](https://github.com/undergroundwires/privacy.sexy/commit/8bbe6ebf750f1a1cbab493fb99b5ea91f4e21609)
* update the screenshot to show off highlighting | [commit](https://github.com/undergroundwires/privacy.sexy/commit/b4aacea2a3e0bbcf2d8a79ff67f51c0f19e888a6)
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.6.2...0.7.0)
## 0.6.2 (2020-08-16) ## 0.6.2 (2020-08-16)
* 🐛 fixed disabling error reporting for november 2019 update | [commit](https://github.com/undergroundwires/privacy.sexy/commit/5967347b80976a519f6f4eb1972a62f3e600df2b) * 🐛 fixed disabling error reporting for november 2019 update | [commit](https://github.com/undergroundwires/privacy.sexy/commit/5967347b80976a519f6f4eb1972a62f3e600df2b)

View File

@@ -15,9 +15,10 @@
## Get started ## Get started
- Online version: [https://privacy.sexy](https://privacy.sexy) - Online version: [https://privacy.sexy](https://privacy.sexy)
- or download latest desktop version for [Windows](https://github.com/undergroundwires/privacy.sexy/releases/download/0.6.2/privacy.sexy-Setup-0.6.2.exe), [Linux](https://github.com/undergroundwires/privacy.sexy/releases/download/0.6.2/privacy.sexy-0.6.2.AppImage), [macOS](https://github.com/undergroundwires/privacy.sexy/releases/download/0.6.2/privacy.sexy-0.6.2.dmg) - or download latest desktop version for [Windows](https://github.com/undergroundwires/privacy.sexy/releases/download/0.7.3/privacy.sexy-Setup-0.7.3.exe), [Linux](https://github.com/undergroundwires/privacy.sexy/releases/download/0.7.3/privacy.sexy-0.7.3.AppImage), [macOS](https://github.com/undergroundwires/privacy.sexy/releases/download/0.7.3/privacy.sexy-0.7.3.dmg)
- 💡 Come back regularly to apply latest version for stronger privacy and security.
[![privacy.sexy application](img/app.png)](https://privacy.sexy) [![privacy.sexy application](img/screenshot.png)](https://privacy.sexy)
## Why ## Why
@@ -48,8 +49,8 @@
- Development: `npm run serve` to compile & hot-reload for development. - Development: `npm run serve` to compile & hot-reload for development.
- Production: `npm run build` to prepare files for distribution. - Production: `npm run build` to prepare files for distribution.
- Or run using Docker: - Or run using Docker:
1. Build: `docker build -t undergroundwires/privacy.sexy:0.6.2 .` 1. Build: `docker build -t undergroundwires/privacy.sexy:0.7.3 .`
2. Run: `docker run -it -p 8080:80 --rm --name privacy.sexy-0.6.2 undergroundwires/privacy.sexy:0.6.2` 2. Run: `docker run -it -p 8080:80 --rm --name privacy.sexy-0.7.3 undergroundwires/privacy.sexy:0.7.3`
## Architecture ## Architecture

View File

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

View File

@@ -1,6 +1,6 @@
{ {
"name": "privacy.sexy", "name": "privacy.sexy",
"version": "0.6.2", "version": "0.7.3",
"author": "undergroundwires", "author": "undergroundwires",
"description": "Enforce privacy & security best-practices on Windows, because privacy is sexy 🍑🍆", "description": "Enforce privacy & security best-practices on Windows, because privacy is sexy 🍑🍆",
"private": true, "private": true,

View File

@@ -52,7 +52,7 @@ function parseCategoryChild(
children.subScripts.push(script); children.subScripts.push(script);
} else { } else {
throw new Error(`Child element is neither a category or a script. throw new Error(`Child element is neither a category or a script.
Parent: ${parent.category}, element: ${categoryOrScript}`); Parent: ${parent.category}, element: ${JSON.stringify(categoryOrScript)}`);
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -41,6 +41,9 @@ function mayBeUniqueLine(codeLine: string): boolean {
if (trimmed === ')' || trimmed === '(') { // "(" and ")" are used often in batch code if (trimmed === ')' || trimmed === '(') { // "(" and ")" are used often in batch code
return false; return false;
} }
if (codeLine.startsWith(':: ') || codeLine.startsWith('REM ')) { // Is comment?
return false;
}
return true; return true;
} }

View File

@@ -1,9 +1,18 @@
import fileSaver from 'file-saver'; import fileSaver from 'file-saver';
export enum FileType {
BatchFile,
}
export class SaveFileDialog { export class SaveFileDialog {
public static saveText(text: string, fileName: string): void { public static saveFile(text: string, fileName: string, type: FileType): void {
this.saveBlob(text, 'text/plain;charset=utf-8', fileName); const mimeType = this.mimeTypes.get(type);
this.saveBlob(text, mimeType, fileName);
} }
private static readonly mimeTypes = new Map<FileType, string>([
// Some browsers (including firefox + IE) require right mime type
// otherwise they ignore extension and save the file as text.
[ FileType.BatchFile, 'application/bat' ], // https://en.wikipedia.org/wiki/Batch_file
]);
private static saveBlob(file: BlobPart, fileType: string, fileName: string): void { private static saveBlob(file: BlobPart, fileType: string, fileName: string): void {
try { try {

View File

@@ -20,6 +20,7 @@ declare module 'liquor-tree' {
// https://github.com/amsik/liquor-tree/blob/master/src/lib/Node.js // https://github.com/amsik/liquor-tree/blob/master/src/lib/Node.js
export interface ILiquorTreeNodeState { export interface ILiquorTreeNodeState {
checked: boolean; checked: boolean;
indeterminate: boolean;
} }
export interface ILiquorTreeNode { export interface ILiquorTreeNode {

View File

@@ -5,9 +5,10 @@ export class LiquorTreeOptions implements ILiquorTreeOptions {
public readonly checkbox = true; public readonly checkbox = true;
public readonly checkOnSelect = true; public readonly checkOnSelect = true;
/* For checkbox mode only. Children will have the same checked state as their parent. /* For checkbox mode only. Children will have the same checked state as their parent.
⚠️ Setting this false, does not update indeterminate state of nodes.
This is false as it's handled manually to be able to batch select for performance + highlighting */ This is false as it's handled manually to be able to batch select for performance + highlighting */
public readonly autoCheckChildren = false; public readonly autoCheckChildren = false;
public readonly parentSelect = false; public readonly parentSelect = true;
public readonly keyboardNavigation = true; public readonly keyboardNavigation = true;
public readonly filter = { // Wrap this in an arrow function as setting filter directly does not work JS APIs public readonly filter = { // Wrap this in an arrow function as setting filter directly does not work JS APIs
emptyText: this.liquorTreeFilter.emptyText, emptyText: this.liquorTreeFilter.emptyText,

View File

@@ -1,14 +1,37 @@
import { ILiquorTreeNode } from 'liquor-tree'; import { ILiquorTreeNode, ILiquorTreeNodeState } from 'liquor-tree';
import { NodeType } from './../../Node/INode'; import { NodeType } from './../../Node/INode';
export function getNewCheckedState( export function getNewState(
oldNode: ILiquorTreeNode, node: ILiquorTreeNode,
selectedNodeIds: ReadonlyArray<string>): ILiquorTreeNodeState {
const checked = getNewCheckedState(node, selectedNodeIds);
const indeterminate = !checked && getNewIndeterminateState(node, selectedNodeIds);
return {
checked, indeterminate,
};
}
function getNewIndeterminateState(
node: ILiquorTreeNode,
selectedNodeIds: ReadonlyArray<string>): boolean { selectedNodeIds: ReadonlyArray<string>): boolean {
switch (oldNode.data.type) { switch (node.data.type) {
case NodeType.Script: case NodeType.Script:
return selectedNodeIds.some((id) => id === oldNode.id); return false;
case NodeType.Category: case NodeType.Category:
return parseAllSubScriptIds(oldNode).every((id) => selectedNodeIds.includes(id)); return parseAllSubScriptIds(node).some((id) => selectedNodeIds.includes(id));
default:
throw new Error('Unknown node type');
}
}
function getNewCheckedState(
node: ILiquorTreeNode,
selectedNodeIds: ReadonlyArray<string>): boolean {
switch (node.data.type) {
case NodeType.Script:
return selectedNodeIds.some((id) => id === node.id);
case NodeType.Category:
return parseAllSubScriptIds(node).every((id) => selectedNodeIds.includes(id));
default: default:
throw new Error('Unknown node type'); throw new Error('Unknown node type');
} }

View File

@@ -23,6 +23,7 @@ export function toNewLiquorTreeNode(node: INode): ILiquorTreeNewNode {
text: node.text, text: node.text,
state: { state: {
checked: false, checked: false,
indeterminate: false,
}, },
children: convertChildren(node.children, toNewLiquorTreeNode), children: convertChildren(node.children, toNewLiquorTreeNode),
data: { data: {

View File

@@ -18,8 +18,6 @@
import { StatefulVue } from '@/presentation/StatefulVue'; import { StatefulVue } from '@/presentation/StatefulVue';
import { INode } from './INode'; import { INode } from './INode';
import { SelectedScript } from '@/application/State/Selection/SelectedScript'; import { SelectedScript } from '@/application/State/Selection/SelectedScript';
import { IApplicationState } from '@/application/State/IApplicationState';
import { getCategoryId, getScriptId } from './../../ScriptNodeParser';
import { getReverter } from './Reverter/ReverterFactory'; import { getReverter } from './Reverter/ReverterFactory';
@Component @Component

View File

@@ -18,14 +18,15 @@
<script lang="ts"> <script lang="ts">
import { Component, Prop, Vue, Watch } from 'vue-property-decorator'; import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
import LiquorTree, { ILiquorTreeNewNode, ILiquorTreeExistingNode, ILiquorTree } from 'liquor-tree'; import LiquorTree from 'liquor-tree';
import Node from './Node/Node.vue'; import Node from './Node/Node.vue';
import { INode } from './Node/INode'; import { INode } from './Node/INode';
import { convertExistingToNode, toNewLiquorTreeNode } from './LiquorTree/NodeWrapper/NodeTranslator'; import { convertExistingToNode, toNewLiquorTreeNode } from './LiquorTree/NodeWrapper/NodeTranslator';
import { INodeSelectedEvent } from './/INodeSelectedEvent'; import { INodeSelectedEvent } from './/INodeSelectedEvent';
import { getNewCheckedState } from './LiquorTree/NodeWrapper/NodeStateUpdater'; import { getNewState } from './LiquorTree/NodeWrapper/NodeStateUpdater';
import { LiquorTreeOptions } from './LiquorTree/LiquorTreeOptions'; import { LiquorTreeOptions } from './LiquorTree/LiquorTreeOptions';
import { FilterPredicate, NodePredicateFilter } from './LiquorTree/NodeWrapper/NodePredicateFilter'; import { FilterPredicate, NodePredicateFilter } from './LiquorTree/NodeWrapper/NodePredicateFilter';
import { ILiquorTreeNewNode, ILiquorTreeExistingNode, ILiquorTree, ILiquorTreeNode, ILiquorTreeNodeState } from 'liquor-tree';
/** Wrapper for Liquor Tree, reveals only abstracted INode for communication */ /** Wrapper for Liquor Tree, reveals only abstracted INode for communication */
@Component({ @Component({
@@ -49,7 +50,7 @@
const initialNodes = this.initialNodes.map((node) => toNewLiquorTreeNode(node)); const initialNodes = this.initialNodes.map((node) => toNewLiquorTreeNode(node));
if (this.selectedNodeIds) { if (this.selectedNodeIds) {
recurseDown(initialNodes, recurseDown(initialNodes,
(node) => node.state.checked = getNewCheckedState(node, this.selectedNodeIds)); (node) => node.state = updateState(node.state, node, this.selectedNodeIds));
} }
this.initialLiquourTreeNodes = initialNodes; this.initialLiquourTreeNodes = initialNodes;
} else { } else {
@@ -82,11 +83,11 @@
@Watch('selectedNodeIds') @Watch('selectedNodeIds')
public setSelectedStatusAsync(selectedNodeIds: ReadonlyArray<string>) { public setSelectedStatusAsync(selectedNodeIds: ReadonlyArray<string>) {
if (!selectedNodeIds) { if (!selectedNodeIds) {
throw new Error('Selected nodes are undefined'); throw new Error('SelectedrecurseDown nodes are undefined');
} }
this.getLiquorTreeApi().recurseDown((node) => { this.getLiquorTreeApi().recurseDown(
node.states.checked = getNewCheckedState(node, selectedNodeIds); (node) => node.states = updateState(node.states, node, selectedNodeIds),
}); );
} }
private getLiquorTreeApi(): ILiquorTree { private getLiquorTreeApi(): ILiquorTree {
@@ -97,6 +98,13 @@
} }
} }
function updateState(
old: ILiquorTreeNodeState,
node: ILiquorTreeNode,
selectedNodeIds: ReadonlyArray<string>): ILiquorTreeNodeState {
return {...old, ...getNewState(node, selectedNodeIds)};
}
function recurseDown( function recurseDown(
nodes: ReadonlyArray<ILiquorTreeNewNode>, nodes: ReadonlyArray<ILiquorTreeNewNode>,
handler: (node: ILiquorTreeNewNode) => void) { handler: (node: ILiquorTreeNewNode) => void) {

View File

@@ -18,7 +18,8 @@ const NothingChosenCode =
.appendCommentLine('-- 🤔 How to use') .appendCommentLine('-- 🤔 How to use')
.appendCommentLine(' 📙 Start by exploring different categories and choosing different tweaks.') .appendCommentLine(' 📙 Start by exploring different categories and choosing different tweaks.')
.appendCommentLine(' 📙 You can select "Recommended" on the top to select "safer" tweaks. Always double check!') .appendCommentLine(' 📙 You can select "Recommended" on the top to select "safer" tweaks. Always double check!')
.appendCommentLine(' 📙 After you choose any tweak, you can download & copy to execute your script.') .appendCommentLine(' 📙 After you choose any tweak, you can download or copy to execute your script.')
.appendCommentLine(' 📙 Come back regularly to apply latest version for stronger privacy and security.')
.appendLine() .appendLine()
.appendCommentLine('-- 🧐 Why privacy.sexy') .appendCommentLine('-- 🧐 Why privacy.sexy')
.appendCommentLine(' ✔️ Rich tweak pool to harden security & privacy of the OS and other softwares on it.') .appendCommentLine(' ✔️ Rich tweak pool to harden security & privacy of the OS and other softwares on it.')
@@ -114,7 +115,7 @@ function initializeEditor(theme: string, editorId: string): ace.Ace.Editor {
min-height: 200px; min-height: 200px;
&__highlight { &__highlight {
background-color:$accent; background-color:$accent;
opacity: 20%; opacity: 0.2; // having procent fails in production (minified) build
position:absolute; position:absolute;
} }
} }

View File

@@ -16,7 +16,7 @@
<script lang="ts"> <script lang="ts">
import { Component } from 'vue-property-decorator'; import { Component } from 'vue-property-decorator';
import { StatefulVue } from './StatefulVue'; import { StatefulVue } from './StatefulVue';
import { SaveFileDialog } from './../infrastructure/SaveFileDialog'; import { SaveFileDialog, FileType } from './../infrastructure/SaveFileDialog';
import { Clipboard } from './../infrastructure/Clipboard'; import { Clipboard } from './../infrastructure/Clipboard';
import IconButton from './IconButton.vue'; import IconButton from './IconButton.vue';
@@ -43,7 +43,7 @@ export default class TheCodeButtons extends StatefulVue {
public async saveCodeAsync() { public async saveCodeAsync() {
const state = await this.getCurrentStateAsync(); const state = await this.getCurrentStateAsync();
SaveFileDialog.saveText(state.code.current, 'privacy-script.bat'); SaveFileDialog.saveFile(state.code.current, 'privacy-script.bat', FileType.BatchFile);
} }
} }
</script> </script>

View File

@@ -2,42 +2,41 @@
@import "@/presentation/styles/colors.scss"; @import "@/presentation/styles/colors.scss";
.tree { .tree {
background-color: $slate; background: $slate;
} &-node {
white-space: normal !important;
.tree-node > .tree-content > .tree-anchor > span { > .tree-content {
color: $white !important; > .tree-anchor > span {
text-transform: uppercase; color: $white;
color: $light-gray; text-transform: uppercase;
font-size: 1.5em; font-size: 1.5em;
} }
&:hover {
.tree-node { background: $dark-gray !important;
white-space: normal !important; }
} }
&.selected { // When using keyboard navigation it higlights current item and its child items
.tree-arrow.has-child { background: $gray;
&.rtl:after, &:after { .tree-text {
border-color: $white !important; color: $black !important;
}
}
}
&-checkbox {
&.checked {
background: $accent !important;
border-color: $accent !important;
}
&.indeterminate {
border-color: $gray !important;
}
background: $dark-slate !important;
}
&-arrow {
&.has-child {
&.rtl:after, &:after {
border-color: $white !important;
}
}
} }
} }
.tree-node.selected > .tree-content {
> .tree-anchor > span {
font-weight: bolder;
}
}
.tree-content:hover {
background: $dark-gray !important;
}
.tree-checkbox {
&.checked {
background: $accent !important;
}
&.indeterminate {
border-color: $gray !important;
}
background: $dark-slate !important;
}

View File

@@ -2,97 +2,189 @@ import 'mocha';
import { expect } from 'chai'; import { expect } from 'chai';
import { ILiquorTreeNode } from 'liquor-tree'; import { ILiquorTreeNode } from 'liquor-tree';
import { NodeType } from '@/presentation/Scripts/ScriptsTree/SelectableTree/Node/INode'; import { NodeType } from '@/presentation/Scripts/ScriptsTree/SelectableTree/Node/INode';
import { getNewCheckedState } from '@/presentation/Scripts/ScriptsTree/SelectableTree/LiquorTree/NodeWrapper/NodeStateUpdater'; import { getNewState } from '@/presentation/Scripts/ScriptsTree/SelectableTree/LiquorTree/NodeWrapper/NodeStateUpdater';
describe('getNewCheckedState', () => { describe('getNewState', () => {
describe('script node', () => { describe('checked', () => {
it('state is true when selected', () => { describe('script node', () => {
// arrange it('true when selected', () => {
const node = getScriptNode(); // arrange
const selectedScriptNodeIds = [ 'a', 'b', node.id, 'c' ]; const node = getScriptNode();
// act const selectedScriptNodeIds = [ 'a', 'b', node.id, 'c' ];
const actual = getNewCheckedState(node, selectedScriptNodeIds); // act
// assert const state = getNewState(node, selectedScriptNodeIds);
expect(actual).to.equal(true); // assert
expect(state.checked).to.equal(true);
});
it('false when unselected', () => {
// arrange
const node = getScriptNode();
const selectedScriptNodeIds = [ 'a', 'b', 'c' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.checked).to.equal(false);
});
}); });
it('state is false when unselected', () => { describe('category node', () => {
// arrange it('true when every child selected', () => {
const node = getScriptNode(); // arrange
const selectedScriptNodeIds = [ 'a', 'b', 'c' ]; const node = {
// act id: '1',
const actual = getNewCheckedState(node, selectedScriptNodeIds); data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
// assert children: [
expect(actual).to.equal(false); { id: '2',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('a'), getScriptNode('b') ],
},
{ id: '3',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('c') ],
},
],
};
const selectedScriptNodeIds = [ 'a', 'b', 'c' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.checked).to.equal(true);
});
it('false when none of the children is selected', () => {
// arrange
const node = {
id: '1',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [
{ id: '2',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('a'), getScriptNode('b') ],
},
{ id: '3',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('c') ],
},
],
};
const selectedScriptNodeIds = [ 'none', 'of', 'them', 'are', 'selected' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.checked).to.equal(false);
});
it('false when some of the children is selected', () => {
// arrange
const node = {
id: '1',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [
{
id: '2',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('a'), getScriptNode('b') ],
},
{
id: '3',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('c') ],
},
],
};
const selectedScriptNodeIds = [ 'a', 'c', 'unrelated' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.checked).to.equal(false);
});
}); });
}); });
describe('category node', () => { describe('indeterminate', () => {
it('state is true when every child selected', () => { describe('script node', () => {
// arrange it('false when selected', () => {
const node = { // arrange
id: '1', const node = getScriptNode();
data: { type: NodeType.Category, documentationUrls: [], isReversible: false }, const selectedScriptNodeIds = [ 'a', 'b', node.id, 'c' ];
children: [ // act
{ id: '2', const state = getNewState(node, selectedScriptNodeIds);
data: { type: NodeType.Category, documentationUrls: [], isReversible: false }, // assert
children: [ getScriptNode('a'), getScriptNode('b') ], expect(state.indeterminate).to.equal(false);
}, });
{ id: '3', it('false when not selected', () => {
data: { type: NodeType.Category, documentationUrls: [], isReversible: false }, // arrange
children: [ getScriptNode('c') ], const node = getScriptNode();
}, const selectedScriptNodeIds = [ 'a', 'b', 'c' ];
], // act
}; const state = getNewState(node, selectedScriptNodeIds);
const selectedScriptNodeIds = [ 'a', 'b', 'c' ]; // assert
// act expect(state.indeterminate).to.equal(false);
const actual = getNewCheckedState(node, selectedScriptNodeIds); });
// assert
expect(actual).to.equal(true);
}); });
it('state is false when none of the children is selected', () => { describe('category node', () => {
// arrange it('false when all children are selected', () => {
const node = { // arrange
id: '1', const node = {
data: { type: NodeType.Category, documentationUrls: [], isReversible: false }, id: '1',
children: [ data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
{ id: '2', children: [
data: { type: NodeType.Category, documentationUrls: [], isReversible: false }, { id: '2',
children: [ getScriptNode('a'), getScriptNode('b') ], data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
}, children: [ getScriptNode('a'), getScriptNode('b') ],
{ id: '3', },
data: { type: NodeType.Category, documentationUrls: [], isReversible: false }, { id: '3',
children: [ getScriptNode('c') ], data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
}, children: [ getScriptNode('c') ],
], },
}; ],
const selectedScriptNodeIds = [ 'none', 'of', 'them', 'are', 'selected' ]; };
// act const selectedScriptNodeIds = [ 'a', 'b', 'c' ];
const actual = getNewCheckedState(node, selectedScriptNodeIds); // act
// assert const state = getNewState(node, selectedScriptNodeIds);
expect(actual).to.equal(false); // assert
}); expect(state.indeterminate).to.equal(false);
it('state is false when some of the children is selected', () => { });
// arrange it('true when all some are selected', () => {
const node = { // arrange
id: '1', const node = {
data: { type: NodeType.Category, documentationUrls: [], isReversible: false }, id: '1',
children: [ data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
{ children: [
id: '2', { id: '2',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false }, data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('a'), getScriptNode('b') ], children: [ getScriptNode('a'), getScriptNode('b') ],
}, },
{ { id: '3',
id: '3', data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
data: { type: NodeType.Category, documentationUrls: [], isReversible: false }, children: [ getScriptNode('c') ],
children: [ getScriptNode('c') ], },
}, ],
], };
}; const selectedScriptNodeIds = [ 'a' ];
const selectedScriptNodeIds = [ 'a', 'c', 'unrelated' ]; // act
// act const state = getNewState(node, selectedScriptNodeIds);
const actual = getNewCheckedState(node, selectedScriptNodeIds); // assert
// assert expect(state.indeterminate).to.equal(true);
expect(actual).to.equal(false); });
it('false when no children are selected', () => {
// arrange
const node = {
id: '1',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [
{ id: '2',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('a'), getScriptNode('b') ],
},
{ id: '3',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('c') ],
},
],
};
const selectedScriptNodeIds = [ 'none', 'of', 'them', 'are', 'selected' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.indeterminate).to.equal(false);
});
}); });
}); });
}); });

View File

@@ -108,6 +108,7 @@ function getNewNode(): ILiquorTreeNewNode {
const base = getNode(); const base = getNode();
const commonState = { const commonState = {
checked: false, checked: false,
indeterminate: false,
}; };
return { return {
id: base.id, id: base.id,

View File

@@ -68,7 +68,7 @@ describe('ScriptReverter', () => {
selection: [ new SelectedScript(script, true)], revert: true, expectRevert: true, selection: [ new SelectedScript(script, true)], revert: true, expectRevert: true,
}, },
{ {
name: 'keeps revert state deselected when already selected wtih non revert state', name: 'keeps revert state deselected when already selected with non revert state',
selection: [ new SelectedScript(script, false)], revert: false, expectRevert: false, selection: [ new SelectedScript(script, false)], revert: false, expectRevert: false,
}, },
]; ];