Compare commits

..

2 Commits

Author SHA1 Message Date
undergroundwires
493fb1ec16 mac: add new scripts and category for services 2023-10-19 01:21:03 +02:00
undergroundwires
b167a69976 Fix YAML error for site release in CI/CD
Fix the syntax error in the GitHub action script that was caused by
improper multi-line YAML notation. This correction ensures the action
can successfully parse and execute.
2023-10-19 00:45:23 +02:00
1229 changed files with 41296 additions and 101932 deletions

View File

@@ -1,11 +1,7 @@
root = true # Top-most EditorConfig file [*.{js,jsx,ts,tsx,vue,sh}]
[*]
end_of_line = lf
[*.{js,jsx,ts,tsx,vue,sh,scss}]
indent_style = space indent_style = space
indent_size = 2 indent_size = 2
end_of_line = lf
trim_trailing_whitespace = true trim_trailing_whitespace = true
insert_final_newline = true insert_final_newline = true
max_line_length = 100 max_line_length = 100
@@ -13,21 +9,3 @@ max_line_length = 100
[{Dockerfile}] [{Dockerfile}]
indent_style = space indent_style = space
indent_size = 4 indent_size = 4
[*.py]
indent_size = 4 # PEP 8 (the official Python style guide) recommends using 4 spaces per indentation level
indent_style = space
max_line_length = 100
[*.ps1]
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
insert_final_newline = true
[*.{scss}] # SASS guidelines: https://archive.today/2024.02.16-232553/https://sass-guidelin.es/
indent_style = space
indent_size = 2 # Recommended by SASS guidelines
max_line_length = 100 # Recommended by SASS guidelines
trim_trailing_whitespace = true
insert_final_newline = true

View File

@@ -9,15 +9,14 @@ module.exports = {
es2022: true, // add globals and sets parserOptions.ecmaVersion to 2022 es2022: true, // add globals and sets parserOptions.ecmaVersion to 2022
}, },
extends: [ extends: [
// Vue specific base rules, `eslint-plugin-vue` // Vue specific rules, eslint-plugin-vue
'plugin:vue/vue3-recommended', 'plugin:vue/essential',
// Extends `eslint-config-airbnb` // Extends eslint-config-airbnb
'@vue/eslint-config-airbnb-with-typescript', '@vue/eslint-config-airbnb-with-typescript',
// - Sets base parser and plugin options. // Extends @typescript-eslint/recommended
// - Includes `plugin:@typescript-eslint/recommended`. But incompatible with // Uses the recommended rules from the @typescript-eslint/eslint-plugin
// `strict-type-checked` and `stylistic-type-checked`, see https://github.com/vuejs/eslint-config-typescript/issues/67.
'@vue/typescript/recommended', '@vue/typescript/recommended',
], ],
rules: { rules: {

View File

@@ -0,0 +1,57 @@
---
name: Bug report (script bug or unexpected script behavior)
about: Create a bug report for generated scripts to help privacy.sexy improve
labels: bug
title: '[BUG]: '
---
<!--
Thank you for reporting an issue with generated script(s).
Please fill in as much of the template below as you're able.
As a small open source project with small community, it can sometimes take a long time for issues to be addressed so please be patient.
-->
### Description
<!--
A clear and concise description of what the bug is.
-->
### OS
<!--
Which OS are you using? What version of OS you were using?
On Windows: Open "Start button" > "Settings" > "System" > "About".
On macOS: Open "Apple menu (top left corner)" > "About This Mac".
On Linux: Open terminal > type: lsb_release -a > copy paste the result.
-->
### Reproduction steps
<!--
How can the bug be recreated?
It's the most important information in the bug report. Bugs that cannot be reproduced cannot be fixed and verified.
E.g.
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
-->
### Scripts
<!--
If applicable, please attach the generated privacy.sexy file instead of copy pasting which becomes too long.
-->
### Screenshots
<!--
If applicable, add screenshots to help explain your problem.
-->
### Additional information
<!--
If applicable, add any other context about the problem here.
-->

View File

@@ -1,114 +0,0 @@
name: "Bug Report: Script Issues"
description: 🐛 Report issues with generated scripts to enhance privacy.sexy
labels: [ 'bug' ]
title: '[Bug]: '
body:
-
type: markdown
attributes:
value: |-
Thank you for contributing to privacy.sexy and guiding our direction! 🌟
Please complete as much of the form below as possible.
Your feedback is valuable, even if you can't provide all details.
-
type: textarea
attributes:
label: Description
description: A clear and concise description of what the bug is.
placeholder: >-
For example: "After running the cleanup script, music playback stopped functioning."
validations:
required: true
-
type: textarea
attributes:
label: How can the bug be recreated?
description: |-
This is the most important information in the bug report.
Bugs that cannot be reproduced cannot be fixed or verified.
placeholder: |-
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
validations:
required: true
-
type: textarea
attributes:
label: Operating system
description: |-
Please specify your operating system and its version.
- On Windows: Open "Start button" > "Settings" > "System" > "About".
- On macOS: Open "Apple menu (top left corner)" > "About This Mac".
- On Linux: Open terminal > type: lsb_release -a > copy paste the result.
placeholder: >-
For example: "Windows 11 Pro 22H3"
validations:
required: false
-
type: textarea
attributes:
label: Script file
description: |-
If applicable, share the generated privacy.sexy file.
GitHub may restrict script file attachments.
Upload your script file to a service like [GitHub Gist](https://gist.github.com/) and share the link here.
If you used the desktop version to run the script, it is already stored on your system.
See the [documentation to locate it](https://github.com/undergroundwires/privacy.sexy/blob/master/docs/desktop/desktop-vs-web-features.md#secure-script-executionstorage).
> **💡 Tip:** You can attach script files by dragging them into this area.
placeholder: |-
Attach the script, or post GitHub Gist link.
For example: https://gist.github.com/privacysexy-forks/6d85ad8ca27acc8c6a5417d4af28c9b6.
validations:
required: false
-
type: textarea
attributes:
label: Screenshots
description: |-
If applicable, add screenshots to help explain your problem.
> **💡 Tip:** You can attach screenshots by clicking this area to highlight it and then pasting them or dragging files in.
placeholder: Attach screenshots here or link to image hosting.
validations:
required: false
-
type: textarea
attributes:
label: Additional information
description: |-
If applicable, add any other context about the problem here.
Helpful information includes:
- Application logs (desktop version only), see: [how to find application logs](https://github.com/undergroundwires/privacy.sexy/blob/master/docs/desktop/desktop-vs-web-features.md#logging).
- Terminal output
- Proposed solutions
- Other related context such as related issues, software behavior, etc.
> **💡 Tip:** You can attach log files by dragging them into this area.
placeholder: >-
For example: "Here are the logs I get from the privacy.sexy 0.13.2 desktop application: ..."
validations:
required: false
-
type: markdown
attributes:
value: |-
---
**✉️ A friendly note from the maintainer:**
> [!NOTE]
> We are a small open-source project with a small community.
> It can sometimes take a long time for issues to be addressed, so please be patient.
> Consider [donating](https://undergroundwires.dev/donate) to keep privacy.sexy alive and improve support ❤️.
> But your issue will eventually get attention regardless.
> <p align="right">@undergroundwires</p>
---

View File

@@ -1,104 +0,0 @@
name: "Bug Report: General"
description: 🐛 Report general issues to enhance privacy.sexy
labels: [ 'bug' ]
title: '[Bug]: '
body:
-
type: markdown
attributes:
value: |-
Thank you for contributing to privacy.sexy and guiding our direction! 🌟
Please complete as much of the form below as possible.
Your feedback is valuable, even if you can't provide all details.
-
type: textarea
attributes:
label: Description
description: Provide a clear and concise description of the issue.
placeholder: >-
For example: "I cannot select any scripts."
validations:
required: true
-
type: textarea
attributes:
label: Reproduction steps
description: |-
This is the most important information in the bug report.
Bugs that cannot be reproduced cannot be fixed or verified.
placeholder: |-
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
validations:
required: true
-
type: textarea
attributes:
label: Expected behavior
description: Describe what you expected to happen when the error occurred.
placeholder: >-
For example: "I expected the settings menu to open smoothly without crashing.".
validations:
required: true
-
type: textarea
attributes:
label: Screenshots
description: |-
If applicable, add screenshots to help explain your problem.
> **💡 Tip:** You can attach screenshots by clicking this area to highlight it and then pasting them or dragging files in.
placeholder: >-
Attach screenshots here or link to image hosting.
validations:
required: false
-
type: textarea
attributes:
label: privacy.sexy environment details
description: |-
If applicable, mention how you were using privacy.sexy when the bug occurred:
- Web (on which operating system and browser?)
- Or desktop (Windows, macOS, or Linux?)
placeholder: >-
For example: "The web version on Edge browser on Windows 11 23H2."
validations:
required: false
-
type: textarea
attributes:
label: Additional context
description: |-
If applicable, add any other context about the problem here.
Helpful information includes:
- Application logs (desktop version only), see: [how to find application logs](https://github.com/undergroundwires/privacy.sexy/blob/master/docs/desktop/desktop-vs-web-features.md#logging).
- Terminal output
- Proposed solutions
- Other related context such as related issues, software behavior, etc.
> **💡 Tip:** You can attach log files by dragging them into this area.
placeholder: >-
For example: "Here are the logs I get from the privacy.sexy 0.13.2 desktop application: ..."
validations:
required: false
-
type: markdown
attributes:
value: |-
---
**✉️ A friendly note from the maintainer:**
> [!NOTE]
> We are a small open-source project with a small community.
> It can sometimes take a long time for issues to be addressed, so please be patient.
> Consider [donating](https://undergroundwires.dev/donate) to keep privacy.sexy alive and improve support ❤️.
> But your issue will eventually get attention regardless.
> <p align="right">@undergroundwires</p>
---

View File

@@ -0,0 +1,55 @@
---
name: Bug report (unrelated to generated scripts)
about: Create a bug report that's not related to generated scripts to help privacy.sexy improve
labels: bug
title: '[BUG]: '
---
<!--
Thank you for reporting an issue.
Please fill in as much of the template below as you're able.
As a small open source project with small community, it can sometimes take a long time for issues to be addressed so please be patient.
-->
### Description
<!--
A clear and concise description of what the bug is.
-->
### Reproduction steps
<!--
It's the most important information in the bug report. Bugs that cannot be reproduced cannot be fixed and verified.
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
-->
### Expected behavior
<!--
A clear and concise description of what you expected to happen.
-->
### Screenshots
<!--
If applicable, add screenshots to help explain your problem.
-->
### Distribution
<!--
If applicable, mention how you were using privacy.sexy when the bug was encountered:
- Web (on Desktop or mobile?)
- Or desktop (Windows, macOS or Linux?)
-->
### Additional context
<!--
If applicable, add any other context about the problem here.
-->

View File

@@ -0,0 +1,36 @@
---
name: Feature request
about: Suggest an idea for privacy.sexy
labels: enhancement
---
<!--
Thank you for suggesting an idea to improve privacy better 🤗.
Please fill in as much of the template below as you're able.
-->
### Problem description
<!--
What are we trying to solve?
Please add a clear and concise description of the problem you are seeking to solve with this feature request.
E.g. I'm always frustrated when [...]
-->
### Proposed solution
<!--
Describe the solution you'd like in a clear and concise manner.
-->
### Alternatives considered
<!--
A clear and concise description of any alternative solutions or features you've considered.
-->
### Additional information
<!--
If applicable, add any other context or screenshots about the feature request here.
-->

View File

@@ -1,73 +0,0 @@
name: "Suggestion: Feature"
description: 💡 Suggest new ideas to enhance privacy.sexy
labels: [ 'enhancement' ]
title: '[Feature]: '
body:
-
type: markdown
attributes:
value: |-
Thank you for contributing to privacy.sexy and guiding our direction! 🌟
Please complete as much of the form below as possible.
Your feedback is valuable, even if you can't provide all details.
-
type: textarea
attributes:
label: Problem statement
description: |-
What are we trying to solve?
Please add a clear and concise description of the problem you are seeking to solve with this feature request.
placeholder: >-
For example: "Every time I use the app, I struggle with..."
validations:
required: true
-
type: textarea
attributes:
label: Proposed solution
description: |-
Describe the solution you'd like in a clear and concise manner.
placeholder: >-
For example: "It would be great if the app could..."
validations:
required: true
-
type: textarea
attributes:
label: Alternatives considered
description: |-
Have you considered any alternative solutions or features?
Different perspectives can inspire new ideas.
placeholder: >-
For example: "We could also solve it by...".
validations:
required: false
-
type: textarea
attributes:
label: Additional information
description: |-
If applicable, add any other context or screenshots about the feature request here.
> **💡 Tip:** You can attach files or screenshots by dragging them into this area.
placeholder: >-
For example: "Challenges can be ..., but I'm unsure about ..., here is some documentation about it: ..."
validations:
required: false
-
type: markdown
attributes:
value: |-
---
**✉️ A friendly note from the maintainer:**
> [!NOTE]
> We are a small open-source project with a small community.
> It can sometimes take a long time for issues to be addressed, so please be patient.
> Consider [donating](https://undergroundwires.dev/donate) to keep privacy.sexy alive and improve support ❤️.
> But your issue will eventually get attention regardless.
> <p align="right">@undergroundwires</p>
---

View File

@@ -0,0 +1,75 @@
---
name: New script suggestion
about: Suggest a new script for privacy.sexy
labels: enhancement
---
<!--
Thank you for suggesting an script to make privacy better. 🤗
Please fill in as much of the template below as you're able.
You could alternatively send a PR directly (see CONTRIBUTING.md).
-->
### OS
<!--
Which OS will the new script configure?
One of the supported OSes: "Windows", "macOS" or "Linux".
-->
### Name
<!--
The name of the script.
It should start with an imperative noun such as "disable", "turn off" , "clear"...
E.g. "Disable webcam telemetry"
-->
### Script code
<!--
Code that will be executed when script is selected.
Try to keep it as simple and backwards-compatible as possible.
Allowed languages:
- Windows: PowerShell (ps1) or batchfile
- 💡 Prioritize the one that's simpler, batchfile if similar.
- macOS: bash (sh)
- Linux: bash (sh) or Python 3
- 💡 Prioritize the one that's simpler, bash if similar.
-->
### Revert code
<!--
If applicable, add code that will revert the script code to its original (OS default) state.
It may require additional time, but it's much appreciated by the community.
Leave blank if the script is nonreversible (e.g. when clearing data without backup).
-->
### Suggested category
<!--
If applicable, suggest one more multiple suitable parent category of script.
A category is the item where the script will be presented under.
Most likely there already is a category for the script, so check the existing categories.
If you're unsure, leave blank and maintainer(s) will choose one.
-->
### Suggested recommendation level
<!--
If applicable, suggest recommending the script or not recommending at all.
A script should be only recommended if it'll be safe for your grandmother to run.
So you have three options here:
STANDARD: Non-breaking scripts that does not limit any functionality.
STRICT: Scripts that can break certain functionality but not intrusive to common daily OS usage.
NONE: Script is not recommended for newbies at all, only those who knows what's going on should select it.
If you're unsure, leave blank and maintainer(s) will choose one.
-->
### Additional documentation/references
<!--
If applicable, refer to documentation that should show up on the script description.
Sources (URLs) should be as high quality as possible e.g. vendor documentation is favored over user forums.
-->

View File

@@ -1,133 +0,0 @@
name: "Suggestion: New Script"
description: 💡 Suggest new scripts to enhance privacy.sexy
labels: [ 'enhancement' ]
title: '[New script]: '
body:
-
type: markdown
attributes:
value: |-
Thank you for contributing to privacy.sexy and guiding our direction! 🌟
Please complete as much of the form below as possible.
Your feedback is valuable, even if you can't provide all details.
For guidance, see our [script guidelines](https://github.com/undergroundwires/privacy.sexy/blob/master/docs/script-guidelines.md).
Consider submitting a PR to get your script added more quickly: (see [CONTRIBUTING.md](https://github.com/undergroundwires/privacy.sexy/blob/master/CONTRIBUTING.md#extend-scripts))
-
type: dropdown
attributes:
label: Operating system
description: Which operating system will the new script configure?
options:
- macOS
- Windows
- Linux
- All of them
validations:
required: false
-
type: textarea
attributes:
label: Name of the script
description: |-
Suggest a name for the script that clearly describes its function.
See [script naming conventions](https://github.com/undergroundwires/privacy.sexy/blob/master/docs/script-guidelines.md#name) for best practices.
placeholder: E.g, "Disable error data submission"
validations:
required: true
-
type: textarea
attributes:
label: Documentation/References
description: |-
Provide any relevant documentation or references.
Prefer high-quality sources such as vendor documentation.
See [documentation guidelines](https://github.com/undergroundwires/privacy.sexy/blob/master/docs/script-guidelines.md#documentation) for best practices.
placeholder: >-
For example: "This script will disable the error data submission, see https://microsoft.com/...".
validations:
required: true
-
type: textarea
attributes:
label: Code
description: |-
If possible, provide or explain the code that the script should execute.
See [script code guidelines](https://github.com/undergroundwires/privacy.sexy/blob/master/docs/script-guidelines.md#code).
placeholder: |-
For example: "Set registry key like this `reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\DataCollection" /v "AllowTelemetry" /t "REG_DWORD" /d "1"`".
validations:
required: false
-
type: textarea
attributes:
label: Revert code
description: |-
If applicable, provide revert code to restore the changes made by the script.
The revert code restores changes to their default state before script execution.
Leave blank for non-reversible scripts.
placeholder: |-
For example: "Revert to operating system default like this `reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\DataCollection" /v "AllowTelemetry" /t "REG_DWORD" /d "0"`".
validations:
required: false
-
type: textarea
attributes:
label: Suggested category
description: |-
Suggest a category for the script.
If unsure, leave blank for maintainers to decide.
placeholder: >-
For example: "Privacy Cleanup > Clear system logs"
-
type: dropdown
attributes:
label: Recommendation level
description: |-
Suggest a recommendation level for the script:
- **Standard**: Recommended for most users without side-effects.
- **Strict**: Provides improved privacy at the cost of some functionality.
- **None**: For advanced users or specific needs.
If unsure, leave blank for maintainers to decide.
options:
- Standard
- Strict
- None (do not recommend)
validations:
required: false
-
type: textarea
attributes:
label: Additional information
description: |-
If applicable, add any other context or screenshots about the script request here.
> **💡 Tip:** You can attach additional documents or screenshots by dragging them into this area or pasting directly.
placeholder: >-
For example: "Challenges can be ..., but I am unsure about ..."
validations:
required: false
-
type: markdown
attributes:
value: |-
---
**✉️ A friendly note from the maintainer:**
> [!NOTE]
> We are a small open-source project with a small community.
> It can sometimes take a long time for issues to be addressed, so please be patient.
> Consider [donating](https://undergroundwires.dev/donate) to keep privacy.sexy alive and improve support ❤️.
> But your issue will eventually get attention regardless.
> <p align="right">@undergroundwires</p>
---

View File

@@ -1,7 +1 @@
# This file must be named `config.yml`. GitHub does not recognize the file if it is named `config.yaml`. blank_issues_enabled: true
blank_issues_enabled: true
contact_links:
- name: Donate
url: https://undergroundwires.dev/donate/
about: ❤️ Donate to support the free software you love to keep it alive.
# A separate link for reporting vulnerabilities is not included here because GitHub generates it automatically.

View File

@@ -1,32 +0,0 @@
# force-ipv4
## Overview
This GitHub action enforces IPv4 for all outgoing network requests. It addresses connectivity issues encountered in GitHub runners, where IPv6 requests may lead to timeouts due to the lack of IPv6 support [1] [2].
## Background
Some applications attempt network connections over IPv6.
Such as requests made by Node's `fetch` API causes `UND_ERR_CONNECT_TIMEOUT` [3] [4] and similar issues [5].
This happens when the software cannot handle this such as by using Happy Eyeballs [6] [7].
## Usage
To use this action in your GitHub workflow, add the following step before any job that requires network access:
```yaml
- name: Enforce IPv4 Connectivity
uses: ./.github/actions/force-ipv4
```
## Note
This action is a workaround addressing specific IPv6-related connectivity issues on GitHub runners and may not be necessary if GitHub's infrastructure evolves to fully support IPv6 in the future.
[1]: https://archive.ph/2024.03.28-185829/https://github.com/actions/runner/issues/3138 "Actions Runner fails on IPv6 only host · Issue #3138 · actions/runner · GitHub | github.com"
[2]: https://archive.ph/2024.03.28-185838/https://github.com/actions/runner-images/issues/668 "IPv6 on GitHub-hosted runners · Issue #668 · actions/runner-images · GitHub | github.com"
[3]: https://archive.ph/2024.03.28-185847/https://github.com/actions/runner/issues/3213 "GitHub runner cannot send `fetch` with `node`, failing with IPv6 DNS error `UND_ERR_CONNECT_TIMEOUT` · Issue #3213 · actions/runner · GitHub | github.com"
[4]: https://archive.ph/2024.03.28-185853/https://github.com/actions/runner-images/issues/9540 "Cannot send outbound requests using node fetch, failing with IPv6 DNS error UND_ERR_CONNECT_TIMEOUT · Issue #9540 · actions/runner-images · GitHub | github.com"
[5]: https://archive.today/2024.03.30-113315/https://github.com/nodejs/node/issues/40537 "\"localhost\" favours IPv6 in node v17, used to favour IPv4 · Issue #40537 · nodejs/node · GitHub"
[6]: https://archive.ph/2024.03.28-185900/https://github.com/nodejs/node/issues/41625 "Happy Eyeballs support (address IPv6 issues in Node 17) · Issue #41625 · nodejs/node · GitHub | github.com"
[7]: https://archive.ph/2024.03.28-185910/https://github.com/nodejs/undici/issues/1531 "fetch times out in under 5 seconds · Issue #1531 · nodejs/undici · GitHub | github.com"

View File

@@ -1,12 +0,0 @@
inputs:
project-root:
required: false
default: '.'
runs:
using: composite
steps:
-
name: Run prefer IPv4 script
shell: bash
run: ./.github/actions/force-ipv4/force-ipv4.sh
working-directory: ${{ inputs.project-root }}

View File

@@ -1,80 +0,0 @@
#!/usr/bin/env bash
main() {
if is_linux; then
echo 'Configuring Linux...'
configure_warp_with_doh_and_ipv6_exclusion_on_linux # [WORKS] Resolves the issue when run independently on GitHub runners lacking IPv6 support.
prefer_ipv4_on_linux # [DOES NOT WORK] It does not resolve the issue when run independently on GitHub runners without IPv6 support.
# Considered alternatives:
# - `sysctl` commands, and direct changes to `/proc/sys/net/` and `/etc/sysctl.conf` led to silent
# Node 18 exits (code: 13) when using `fetch`.
elif is_macos; then
echo 'Configuring macOS...'
configure_warp_with_doh_and_ipv6_exclusion_on_macos # [WORKS] Resolves the issue when run independently on GitHub runners lacking IPv6 support.
disable_ipv6_on_macos # [WORKS INCONSISTENTLY] Resolves the issue inconsistently when run independently on GitHub runners without IPv6 support.
fi
echo "IPv4: $(curl --ipv4 --silent --max-time 15 --retry 3 --user-agent Mozilla https://api.ip.sb/geoip)"
echo "IPv6: $(curl --ipv6 --silent --max-time 15 --retry 3 --user-agent Mozilla https://api.ip.sb/geoip)"
}
is_linux() {
[[ "$(uname -s)" == "Linux" ]]
}
is_macos() {
[[ "$(uname -s)" == "Darwin" ]]
}
configure_warp_with_doh_and_ipv6_exclusion_on_linux() {
install_warp_on_debian
configure_warp_doh_and_exclude_ipv6
}
configure_warp_with_doh_and_ipv6_exclusion_on_macos() {
brew install cloudflare-warp
configure_warp_doh_and_exclude_ipv6
}
configure_warp_doh_and_exclude_ipv6() {
echo 'Beginning configuration of the Cloudflare WARP client with DNS-over-HTTPS and IPv6 exclusion...'
echo 'Initiating client registration with Cloudflare...'
warp-cli --accept-tos registration new
echo 'Configuring WARP to operate in DNS-over-HTTPS mode (warp+doh)...'
warp-cli --accept-tos mode warp+doh
echo 'Excluding IPv6 traffic from WARP by configuring it as a split tunnel...'
warp-cli --accept-tos add-excluded-route '::/0' # Exclude IPv6, forcing IPv4 resolution
# `tunnel ip add` does not work with IP ranges, see https://community.cloudflare.com/t/cant-cidr-for-split-tunnling/630834
echo 'Establishing WARP connection...'
warp-cli --accept-tos connect
}
install_warp_on_debian() {
curl -fsSL https://pkg.cloudflareclient.com/pubkey.gpg | sudo gpg --yes --dearmor --output /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.com/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/cloudflare-client.list
sudo apt-get update
sudo apt-get install -y cloudflare-warp
}
disable_ipv6_on_macos() {
networksetup -listallnetworkservices \
| tail -n +2 \
| while IFS= read -r interface; do
echo "Disabling IPv6 on: $interface..."
networksetup -setv6off "$interface"
done
}
prefer_ipv4_on_linux() {
local -r gai_config_file_path='/etc/gai.conf'
if [ ! -f "$gai_config_file_path" ]; then
echo "Creating $gai_config_file_path since it doesn't exist..."
touch "$gai_config_file_path"
fi
echo "precedence ::ffff:0:0/96 100" | sudo tee -a "$gai_config_file_path" > /dev/null
echo "Configuration complete."
}
main

View File

@@ -1,12 +0,0 @@
inputs:
project-root:
required: false
default: '.'
runs:
using: composite
steps:
-
name: Install ImageMagick
shell: bash
run: ./.github/actions/install-imagemagick/install-imagemagick.sh
working-directory: ${{ inputs.project-root }}

View File

@@ -1,56 +0,0 @@
#!/usr/bin/env bash
main() {
local install_command
if ! install_command=$(get_install_command); then
fatal_error 'Could not find available command to install'
fi
if ! eval "$install_command"; then
echo "Failed to install ImageMagick. Command: ${install_command}"
exit 1
fi
echo 'ImageMagick installation completed successfully'
}
get_install_command() {
case "$OSTYPE" in
darwin*)
ensure_command_exists 'brew'
echo 'brew install imagemagick'
;;
linux-gnu*)
if is_ubuntu; then
ensure_command_exists 'apt'
echo 'sudo apt install -y imagemagick'
else
fatal_error 'Unsupported Linux distribution'
fi
;;
msys*|cygwin*)
ensure_command_exists 'choco'
echo 'choco install -y imagemagick'
;;
*)
fatal_error "Unsupported operating system: $OSTYPE"
;;
esac
}
ensure_command_exists() {
local -r command="$1"
if ! command -v "$command" >/dev/null 2>&1; then
fatal_error "Command missing: $command"
fi
}
fatal_error() {
local -r error_message="$1"
>&2 echo "$error_message"
exit 1
}
is_ubuntu() {
[ -f /etc/os-release ] && grep -qi 'ubuntu' /etc/os-release
}
main

View File

@@ -3,7 +3,6 @@ runs:
steps: steps:
- -
name: Setup node name: Setup node
uses: actions/setup-node@v4 uses: actions/setup-node@v3
with: with:
node-version: 20.x node-version: 16.x
# check-latest: true # Newest versions can potentially have undiscovered bugs or regressions

View File

@@ -1,15 +0,0 @@
inputs:
name:
required: true
path:
required: true
runs:
using: composite
steps:
-
name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.name }}
path: ${{ inputs.path }}

View File

@@ -72,19 +72,16 @@ jobs:
build-docker: build-docker:
strategy: strategy:
matrix: matrix:
os: os: [ macos, ubuntu ] # Windows runners do not support Linux containers
- macos-13 # Downgraded due to lack of nested virtualization support in ARM-based runners (See: actions/runner-images#9460, actions/runner-images#9741, abiosoft/colima#1023)
- ubuntu-latest
# - windows-latest # Windows runners do not support Linux containers
fail-fast: false # Allows to see results from other combinations fail-fast: false # Allows to see results from other combinations
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}-latest
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- -
name: Install Docker on macOS name: Install Docker on macOS
if: contains(matrix.os, 'macos') # macOS runner is missing Docker if: matrix.os == 'macos' # macOS runner is missing Docker
run: |- run: |-
# Install Docker # Install Docker
brew install docker brew install docker
@@ -98,12 +95,6 @@ jobs:
- -
name: Run Docker image on port 8080 name: Run Docker image on port 8080
run: docker run -d -p 8080:80 --rm --name privacy.sexy undergroundwires/privacy.sexy:latest run: docker run -d -p 8080:80 --rm --name privacy.sexy undergroundwires/privacy.sexy:latest
-
name: Enforce IPv4 Connectivity # Used due to GitHub runners' lack of IPv6 support, preventing request timeouts.
uses: ./.github/actions/force-ipv4
- -
name: Check server is up and returns HTTP 200 name: Check server is up and returns HTTP 200
run: >- run: node ./scripts/verify-web-server-status.js --url http://localhost:8080
node ./scripts/verify-web-server-status.js \
--url http://localhost:8080 \
--max-retries ${{ matrix.os == 'macos' && '90' || '30' }}

View File

@@ -9,13 +9,9 @@ jobs:
run-check: run-check:
strategy: strategy:
matrix: matrix:
os: os: [ macos, ubuntu, windows ]
- macos-latest # Apple silicon (ARM64)
- macos-13 # Intel-based (x86-64)
- ubuntu-latest
- windows-latest
fail-fast: false # Allows to see results from other combinations fail-fast: false # Allows to see results from other combinations
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}-latest
steps: steps:
- -
name: Checkout name: Checkout
@@ -26,12 +22,9 @@ jobs:
- -
name: Install dependencies name: Install dependencies
uses: ./.github/actions/npm-install-dependencies uses: ./.github/actions/npm-install-dependencies
-
name: Install ImageMagick # For screenshots
uses: ./.github/actions/install-imagemagick
- -
name: Configure Ubuntu name: Configure Ubuntu
if: contains(matrix.os, 'ubuntu') if: matrix.os == 'ubuntu'
shell: bash shell: bash
run: |- run: |-
sudo apt update sudo apt update
@@ -59,20 +52,11 @@ jobs:
sudo Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & sudo Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
echo "DISPLAY=:99" >> $GITHUB_ENV echo "DISPLAY=:99" >> $GITHUB_ENV
# Install ImageMagick for screenshots
sudo apt install -y imagemagick
# Install xdotool and xprop (from x11-utils) for window title capturing # Install xdotool and xprop (from x11-utils) for window title capturing
sudo apt install -y xdotool x11-utils sudo apt install -y xdotool x11-utils
# Workaround for Electron AppImage apps failing to initialize on Ubuntu 24.04 due to AppArmor restrictions
# Disables unprivileged user namespaces restriction to allow Electron apps to run
# Reference: https://github.com/electron/electron/issues/42510
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
# Workaround for Mesa driver issues on Ubuntu 24.04
# Installs latest Mesa drivers from Kisak PPA
# Reference: https://askubuntu.com/q/1516040
sudo add-apt-repository ppa:kisak/kisak-mesa
sudo apt update
sudo apt upgrade
- -
name: Test name: Test
shell: bash shell: bash
@@ -82,7 +66,7 @@ jobs:
- -
name: Upload screenshot name: Upload screenshot
if: always() # Run even if previous step fails if: always() # Run even if previous step fails
uses: ./.github/actions/upload-artifact uses: actions/upload-artifact@v3
with: with:
name: screenshot-${{ matrix.os }} name: screenshot-${{ matrix.os }}
path: screenshot.png path: screenshot.png

View File

@@ -1,7 +1,6 @@
name: checks.external-urls name: checks.external-urls
on: on:
push:
schedule: schedule:
- cron: '0 0 * * 0' # at 00:00 on every Sunday - cron: '0 0 * * 0' # at 00:00 on every Sunday
@@ -18,13 +17,6 @@ jobs:
- -
name: Install dependencies name: Install dependencies
uses: ./.github/actions/npm-install-dependencies uses: ./.github/actions/npm-install-dependencies
-
name: Enforce IPv4 Connectivity # Used due to GitHub runners' lack of IPv6 support, preventing request timeouts.
uses: ./.github/actions/force-ipv4
- -
name: Test name: Test
run: npm run check:external-urls run: npm run check:external-urls
env:
RANDOMIZED_URL_CHECK_LIMIT: "${{ github.event_name == 'push' && '100' || '3000' }}"
# - Scheduled checks has high limit for thorough testing.
# - For push events, triggered by code changes, the amount of URLs are limited to provide quick feedback.

View File

@@ -1,19 +1,18 @@
name: checks.quality name: quality-checks
on: [ push, pull_request ] on: [ push, pull_request ]
jobs: jobs:
lint: lint:
runs-on: ${{ matrix.os }}-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
lint-command: lint-command:
- npm run lint:eslint - npm run lint:eslint
- npm run lint:yaml - npm run lint:yaml
- npm run lint:md - npm run lint:md
- npm run lint:md:consistency
- npm run lint:md:relative-urls - npm run lint:md:relative-urls
- npm run lint:md:external-urls - npm run lint:md:consistency
os: [ macos, ubuntu, windows ] os: [ macos, ubuntu, windows ]
fail-fast: false # Still interested to see results from other combinations fail-fast: false # Still interested to see results from other combinations
steps: steps:
@@ -29,74 +28,3 @@ jobs:
- -
name: Lint name: Lint
run: ${{ matrix.lint-command }} run: ${{ matrix.lint-command }}
todo-check:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Scan latest commit for TODO comments
shell: bash
run: |-
readonly todo_comment_search_pattern='TODO'':' # Define search pattern in parts to prevent IDE from flagging this script line as a TODO item
if git grep "$todo_comment_search_pattern" HEAD; then
echo 'TODO comments found in the latest commit.'
exit 1
else
echo 'No TODO comments found in the latest commit.'
exit 0
fi
pylint:
runs-on: ${{ matrix.os }}-latest
strategy:
matrix:
os: [ macos, ubuntu, windows ]
fail-fast: false # Still interested to see results from other combinations
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Setup node
uses: ./.github/actions/setup-node
-
name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
-
name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pylint
-
name: Analyzing the code with pylint
run: npm run lint:pylint
validate-collection-files:
runs-on: ${{ matrix.os }}-latest
strategy:
matrix:
os: [ macos, ubuntu, windows ]
fail-fast: false # Still interested to see results from other combinations
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Setup node
uses: ./.github/actions/setup-node
-
name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
-
name: Install dependencies
run: python3 -m pip install -r ./scripts/validate-collections-yaml/requirements.txt
-
name: Validate
run: python3 ./scripts/validate-collections-yaml

View File

@@ -9,15 +9,12 @@ jobs:
runs-on: ${{ matrix.os }}-latest runs-on: ${{ matrix.os }}-latest
strategy: strategy:
matrix: matrix:
os: [macos, ubuntu, windows] os: [ macos, ubuntu, windows ]
fail-fast: false # Still interested to see results from other combinations fail-fast: false # Still interested to see results from other combinations
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
-
name: Install ImageMagick
uses: ./.github/actions/install-imagemagick
- -
name: Setup node name: Setup node
uses: ./.github/actions/setup-node uses: ./.github/actions/setup-node
@@ -56,31 +53,3 @@ jobs:
- -
name: Run install-deps name: Run install-deps
run: ${{ matrix.install-command }} run: ${{ matrix.install-command }}
configure-vscode:
runs-on: ${{ matrix.os.name }}-latest
strategy:
matrix:
os:
- name: macos
install-vscode-command: brew install --cask visual-studio-code
- name: ubuntu
install-vscode-command: sudo snap install code --classic
- name: windows
install-vscode-command: choco install vscode
fail-fast: false # Still interested to see results from other combinations
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
-
name: Install VSCode
run: ${{ matrix.os.install-vscode-command }}
-
name: Configure VSCode
run: python3 ./scripts/configure_vscode.py

View File

@@ -20,7 +20,6 @@ jobs:
fetch-depth: 0 # fetch all history fetch-depth: 0 # fetch all history
- -
name: Checkout to bump commit name: Checkout to bump commit
shell: bash
run: git checkout "$(git rev-list "${{ github.event.release.tag_name }}"..master | tail -1)" run: git checkout "$(git rev-list "${{ github.event.release.tag_name }}"..master | tail -1)"
- -
name: Setup node name: Setup node

View File

@@ -24,41 +24,3 @@ jobs:
- -
name: Run e2e tests name: Run e2e tests
run: npm run test:cy:run run: npm run test:cy:run
-
name: Output artifact directories
id: artifacts
if: always() # Run even if previous steps fail because test run video is always captured
shell: bash
run: |-
declare -r dirs_json_file='cypress-dirs.json'
if [ ! -f "${dirs_json_file}" ]; then
echo "${dirs_json_file} does not exist"
exit 1
fi
SCREENSHOTS_DIR=$(jq -r '.screenshots' "${dirs_json_file}")
VIDEOS_DIR=$(jq -r '.videos' "${dirs_json_file}")
for dir in "${SCREENSHOTS_DIR}" "${VIDEOS_DIR}"; do
if [ "${dir}" = 'null' ] || [ -z "${dir}" ]; then
echo "One or more directories are null or not specified in cypress-dirs.json"
exit 1
fi
done
echo "SCREENSHOTS_DIR=${SCREENSHOTS_DIR}" >> "${GITHUB_OUTPUT}"
echo "VIDEOS_DIR=${VIDEOS_DIR}" >> "${GITHUB_OUTPUT}"
-
name: Upload screenshots
if: failure() # Run only if previous steps fail because screenshots will be generated only if E2E test failed
uses: ./.github/actions/upload-artifact
with:
name: e2e-screenshots-${{ matrix.os }}
path: ${{ steps.artifacts.outputs.SCREENSHOTS_DIR }}
-
name: Upload videos
if: always() # Run even if previous steps fail because test run video is always captured
uses: ./.github/actions/upload-artifact
with:
name: e2e-videos-${{ matrix.os }}
path: ${{ steps.artifacts.outputs.VIDEOS_DIR }}

21
.gitignore vendored
View File

@@ -1,20 +1,5 @@
# Application build artifacts
/dist-*/
# npm
node_modules node_modules
/dist-*/
# Visual Studio Code .vs
.vscode/**/* .vscode/**/*
!.vscode/extensions.json !.vscode/extensions.json
# draw.io
*.bkp
*.dtmp
# macOS
.DS_Store
# Python
__pycache__
.venv

View File

@@ -5,10 +5,8 @@
"wengerk.highlight-bad-chars", // Highlights bad chars. "wengerk.highlight-bad-chars", // Highlights bad chars.
"wayou.vscode-todo-highlight", // Highlights TODO. "wayou.vscode-todo-highlight", // Highlights TODO.
"wix.vscode-import-cost", // Shows in KB how much a require include in code. "wix.vscode-import-cost", // Shows in KB how much a require include in code.
// Markdown // Documentation
"davidanson.vscode-markdownlint", // Lints markdown. "davidanson.vscode-markdownlint", // Lints markdown.
// YAML
"redhat.vscode-yaml", // Lints YAML files, validates against schema.
// TypeScript / JavaScript // TypeScript / JavaScript
"dbaeumer.vscode-eslint", // Lints JavaScript/TypeScript. "dbaeumer.vscode-eslint", // Lints JavaScript/TypeScript.
"pmneo.tsimporter", // Provides better auto-complete for TypeScripts imports. "pmneo.tsimporter", // Provides better auto-complete for TypeScripts imports.
@@ -18,8 +16,7 @@
// Scripting // Scripting
"timonwong.shellcheck", // Lints bash files. "timonwong.shellcheck", // Lints bash files.
"ms-vscode.powershell", // Lints PowerShell files. "ms-vscode.powershell", // Lints PowerShell files.
"ms-python.python", // Python IntelliSense, debugging, and basic linting. "ms-python.python", // Lints Python files.
"ms-python.pylint", // Lints Python files
// Distribution // Distribution
"ms-azuretools.vscode-docker" // Adds Docker support. "ms-azuretools.vscode-docker" // Adds Docker support.
] ]

View File

@@ -1,296 +1,5 @@
# Changelog # Changelog
## 0.13.6 (2024-08-13)
* win: improve service disabling as TrustedInstaller | [5d365f6](https://github.com/undergroundwires/privacy.sexy/commit/5d365f65fa0e34925b16b2eac2af53c31e34e99a)
* Fix documentation button spacing on small screens | [70959cc](https://github.com/undergroundwires/privacy.sexy/commit/70959ccadafac5abcfa83e90cdb0537890b05f14)
* Fix close button overlap by scrollbar | [19ea8db](https://github.com/undergroundwires/privacy.sexy/commit/19ea8dbc5bc2dc436200cd40bf2a84c3fc3c6471)
* win: refactor version-specific actions | [0239b52](https://github.com/undergroundwires/privacy.sexy/commit/0239b523859d5c2b80033cc03f0248a9af35f28f)
* win: support Microsoft Store Firefox installations | [8d7a7eb](https://github.com/undergroundwires/privacy.sexy/commit/8d7a7eb434b2d83e32fa758db7e6798849bad41c)
* Refactor text utilities and expand their usage | [851917e](https://github.com/undergroundwires/privacy.sexy/commit/851917e049c41c679644ddbe8ad4b6e45e5c8f35)
* Bump dependencies to latest | [dd7239b](https://github.com/undergroundwires/privacy.sexy/commit/dd7239b8c14027274926279a4c8c7e5845b55558)
* Refactor styles to match new CSS nesting behavior | [abe03ce](https://github.com/undergroundwires/privacy.sexy/commit/abe03cef3f691f6e56faee991cd2da9c45244279)
* Improve compiler error display for latest Chromium | [b16e136](https://github.com/undergroundwires/privacy.sexy/commit/b16e13678ce1b8a6871eba8196e82bb321410067)
* Fix intermittent `ModalDialog` unit test failures | [a650558](https://github.com/undergroundwires/privacy.sexy/commit/a6505587bf4a448f5f3de930004a95ee203416b8)
* Ensure tests do not log warning or errors | [ae0165f](https://github.com/undergroundwires/privacy.sexy/commit/ae0165f1fe7dba9dd8ddaa1afa722a939772d3b6)
* win: improve disabling SmartScreen #385 | [11e566d](https://github.com/undergroundwires/privacy.sexy/commit/11e566d0e5177214a2600f3fd2097aea62373b24)
* win: unify registry setting as TrustedInstaller | [8526d25](https://github.com/undergroundwires/privacy.sexy/commit/8526d2510b34cbd7e79342f79d444419f601b186)
* win: improve, fix, restructure CEIP disabling | [c2d3cdd](https://github.com/undergroundwires/privacy.sexy/commit/c2d3cddc47d8d4b34bff63d959612919fa971012)
* win: centralize, improve Defender data collection | [b185255](https://github.com/undergroundwires/privacy.sexy/commit/b185255a0a72d5bfa96d6cf60f868ecc67149d68)
* win: fix and document VStudio license removal | [109fc01](https://github.com/undergroundwires/privacy.sexy/commit/109fc01c9a047002c4309e7f8a2ca4647c494a8a)
* win: improve registry/recent cleaning | [48d97af](https://github.com/undergroundwires/privacy.sexy/commit/48d97afdf6c2964cab7951208e1b0a02c3fd4c9b)
* Relax linting to allow null recommendation | [6fbc816](https://github.com/undergroundwires/privacy.sexy/commit/6fbc81675f7f063c4ee2502b8d9f169aacb39ae4)
* Refactor executable IDs to use strings #262 | [ded55a6](https://github.com/undergroundwires/privacy.sexy/commit/ded55a66d6044a03d4e18330e146b69d159509a3)
* win: fix, improve and unify Windows version logic | [f89c232](https://github.com/undergroundwires/privacy.sexy/commit/f89c2322b05d19b82914b20416ecefd7bc7e3702)
* Fix PowerShell code block inlining in compiler | [d77c3cb](https://github.com/undergroundwires/privacy.sexy/commit/d77c3cbbe212d9929e083181cc331b45d01e2883)
* win: improve registry value deletion #381 | [55c23e9](https://github.com/undergroundwires/privacy.sexy/commit/55c23e9d4cee3b7f74c26a4ac8516535048d67f2)
* win: improve folder hiding in "This PC" #16 | [e8add5e](https://github.com/undergroundwires/privacy.sexy/commit/e8add5ec08d2e8b7636cc9c8f0f9a33e4b004265)
* win: improve Microsoft Edge associations removal | [c2f4b68](https://github.com/undergroundwires/privacy.sexy/commit/c2f4b6878635e97f9c4be7bf2ee194a2deebb38a)
* win: unify registry data setting, fix #380 | [4cea6b2](https://github.com/undergroundwires/privacy.sexy/commit/4cea6b26ec2717c792c2471cc587f370274f90c4)
* win: improve disabling NCSI #189, #216, #279 | [c7e57b8](https://github.com/undergroundwires/privacy.sexy/commit/c7e57b8913f409a1c149ba598dc2f8786df0f9a9)
* win, mac: fix minor typos, formatting, dead URLs | [29e1069](https://github.com/undergroundwires/privacy.sexy/commit/29e1069bf2bc317e3c255b38c1ba0ab078b42d98)
* win: fix, constrain and document WNS #227 #314 | [50ba00b](https://github.com/undergroundwires/privacy.sexy/commit/50ba00b0af6232fc9187532635b04c4d9d9a68af)
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.13.5...0.13.6)
## 0.13.5 (2024-06-26)
* ci/cd: centralize and bump artifact uploads | [22d6c79](https://github.com/undergroundwires/privacy.sexy/commit/22d6c7991eb2c138578a7d41950f301906dbf703)
* win: document and improve Firefox telemetry #259 | [8341411](https://github.com/undergroundwires/privacy.sexy/commit/8341411be434c6d145e942b1792020ccf02f58c8)
* Add image to `README.md` to thank supporters | [fa2a92b](https://github.com/undergroundwires/privacy.sexy/commit/fa2a92bf893933bf5cd04512a712b7aa1b921277)
* win: improve executable blocking, Chrome reporting | [f21ef92](https://github.com/undergroundwires/privacy.sexy/commit/f21ef9250a2f459dbd4f789d857c78298fc202e6)
* mac: discourage and document captive portal script | [b29cd7b](https://github.com/undergroundwires/privacy.sexy/commit/b29cd7b5f74accf92c9700c3171670f82c8cb3b3)
* win: fix revert scripts for removing shortcuts | [8becc7d](https://github.com/undergroundwires/privacy.sexy/commit/8becc7dbc46af4441900e9841a716a53735bc82e)
* Refactor to unify scripts/categories as Executable | [c138f74](https://github.com/undergroundwires/privacy.sexy/commit/c138f74460bafaba3da55a65f3942bb6f95b1d99)
* Add object property validation in parser #369 | [6ecfa9b](https://github.com/undergroundwires/privacy.sexy/commit/6ecfa9b954edc10401acaf5c735eec0fc9f991cd)
* win: fix missing app access recommendations #369 | [1c2d82d](https://github.com/undergroundwires/privacy.sexy/commit/1c2d82dc9bd412ea601ab2550ba0b4f7d144f8e8)
* win: fix text and handwriting script omission #369 | [1a10cf2](https://github.com/undergroundwires/privacy.sexy/commit/1a10cf2e5f87cd8eb421ef77f6ce764b5482515e)
* mac: document, improve, encourage clearing logs | [e9a5285](https://github.com/undergroundwires/privacy.sexy/commit/e9a52859f63609c3f56def0b3e4d1ac6e5661536)
* Add schema validation for collection files #369 | [dc03bff](https://github.com/undergroundwires/privacy.sexy/commit/dc03bff324d673101002bb16f14e0429e8170fbb)
* win: fix incomplete VSCEIP, location scripts | [48761f6](https://github.com/undergroundwires/privacy.sexy/commit/48761f62a242f0910307994271cbe6730fb30f7e)
* Add type validation for parameters and fix types | [fac26a6](https://github.com/undergroundwires/privacy.sexy/commit/fac26a6ca07479c84fe62c5ea2a572dad1898ef8)
* Bump Electron to latest | [ed93614](https://github.com/undergroundwires/privacy.sexy/commit/ed93614ca34b1ab166e645cc5bedd497b0caeaac)
* Trim compiler error output for better readability | [78c62cf](https://github.com/undergroundwires/privacy.sexy/commit/78c62cfc953dbba543d8bdc42828a4ef4b13a7c7)
* win: fix errors due to missing Edge uninstaller | [2f82873](https://github.com/undergroundwires/privacy.sexy/commit/2f828735a87f98ba87b4fc826823d1482d4f2db2)
* win: fix latest Edge removal on Windows 10 #309 | [e7031a3](https://github.com/undergroundwires/privacy.sexy/commit/e7031a3ae4e57b6522c6ca67fc30e8a8718506b2)
* win: categorize, rename, doc Chrome & Edge scripts | [f286f92](https://github.com/undergroundwires/privacy.sexy/commit/f286f92b1fec49e89eea8982dffbc3d6ef1defde)
* win: add disabling Edge/WebView2 auto-updates #309 | [ed7e69c](https://github.com/undergroundwires/privacy.sexy/commit/ed7e69c07efe83fdb7f4af13aa220ff991fbbe59)
* win, linux, mac: fix typos #373 | [c09c5ff](https://github.com/undergroundwires/privacy.sexy/commit/c09c5ffa47865f7c76910644558b6783ed44f1e4)
* win: add more Edge scripts including AI & ads | [1430d52](https://github.com/undergroundwires/privacy.sexy/commit/1430d5215ab094d8201710761d631dc2bd740918)
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.13.4...0.13.5)
## 0.13.4 (2024-05-27)
* Add specific empty function name compiler error | [870120b](https://github.com/undergroundwires/privacy.sexy/commit/870120bc13909a3681e0f0a2351806849476342f)
* ci/cd: fix recent Docker build failures on macOS | [a1922c5](https://github.com/undergroundwires/privacy.sexy/commit/a1922c50c12b3b7806e9e681ace842194a178bda)
* win: standardize registry edit + delete on revert | [cec0b4b](https://github.com/undergroundwires/privacy.sexy/commit/cec0b4b4f63c3563a0e7923ce6324a38d71a3955)
* Fix e2e test failing on Windows | [4a7efa2](https://github.com/undergroundwires/privacy.sexy/commit/4a7efa27c8df73ef9b7960afed29f216b066cba2)
* Add support for macOS universal binary #348, #362 | [d25c4e8](https://github.com/undergroundwires/privacy.sexy/commit/d25c4e8c812b8d012010ba38070a2931dcd28908)
* Migrate to GitHub issue forms | [9ab3ff7](https://github.com/undergroundwires/privacy.sexy/commit/9ab3ff75b0a69ac2ba27dd02e82db9b5bd76ea0f)
* ci/cd: fix quality checks not running on all OSes | [2390530](https://github.com/undergroundwires/privacy.sexy/commit/2390530d929fb92c266558c52376569a0ecb90c1)
* Bump Vue to latest and fix universal selector CSS | [aae5434](https://github.com/undergroundwires/privacy.sexy/commit/aae54344511ec51d17ad0420a92cb5a064e0e7bb)
* Centralize and optimize `ResizeObserver` usage | [2923621](https://github.com/undergroundwires/privacy.sexy/commit/292362135db0519ec1050bab80ed373aad115731)
* win: improve app access disabling and docs #138 | [ff3d5c4](https://github.com/undergroundwires/privacy.sexy/commit/ff3d5c48419f663379f5aba8936636c22f2c5de8)
* win: document and discourage RSA key script #363 | [f347fde](https://github.com/undergroundwires/privacy.sexy/commit/f347fde0c85f8b51b0060fdea0a2724b042aaeed)
* win: improve printing removal /w Print Queue #279 | [150e067](https://github.com/undergroundwires/privacy.sexy/commit/150e0670392bb62348c20ec644a4ed8a6bbffe74)
* win: discourage blocking app access #121 #339 #350 | [7794846](https://github.com/undergroundwires/privacy.sexy/commit/77948461856e6837ddfbcbbef72a1bf9fc706b4e)
* Improve context for errors thrown by compiler | [4212c7b](https://github.com/undergroundwires/privacy.sexy/commit/4212c7b9e0b1500378a1e4e88efc2d59f39f3d29)
* win: document disabling firewall #115 #152 #364 | [12b1f18](https://github.com/undergroundwires/privacy.sexy/commit/12b1f183f7ce966d6ce090d98aeea7ec491f8c7c)
* win: add script to disable Recall feature | [ce4cfdd](https://github.com/undergroundwires/privacy.sexy/commit/ce4cfdd169b7da0edc3da61143c988ed5f3c976e)
* win, mac, linux: fix typos and dead URLs #367 | [9e34e64](https://github.com/undergroundwires/privacy.sexy/commit/9e34e644493674ca709b64a47206763d5d4bd60c)
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.13.3...0.13.4)
## 0.13.3 (2024-05-11)
* win: organize and document network disablement | [2eed6f4](https://github.com/undergroundwires/privacy.sexy/commit/2eed6f4afb6cf85fdc1d6acb808f82405a35cafd)
* win: improve disabling SMBv1 protocol | [f584fab](https://github.com/undergroundwires/privacy.sexy/commit/f584fabb50c7de70ba43751d721af94d8fa2fa8a)
* win: improve disabling insecure renegotiations | [f261ab4](https://github.com/undergroundwires/privacy.sexy/commit/f261ab4cd9a53e31325e5c6da9129542971fe84b)
* win: doc, improve, encourage cipher disabling | [8b224ee](https://github.com/undergroundwires/privacy.sexy/commit/8b224eefe71be6a556a1085d8fe20dbd4b889430)
* ci/cd: add check for TODO comments | [4e21f05](https://github.com/undergroundwires/privacy.sexy/commit/4e21f05031d6cc90cda684bd598bec4735f8103b)
* win: improve 'Snipping Tool' removal #343 | [e18907c](https://github.com/undergroundwires/privacy.sexy/commit/e18907ca91e483255b44d14d7d923d7eef92afbd)
* ci/cd: lint Python scripts using `pylint` | [23bac0f](https://github.com/undergroundwires/privacy.sexy/commit/23bac0fc76ad697abb34f3fb327df5cdeb40286a)
* win: improve disabling insecure hashes #131 | [d19dde6](https://github.com/undergroundwires/privacy.sexy/commit/d19dde603ddac47022ee2e0ea865d53857560c26)
* Add system requirements documentation #134 | [0fc2ffc](https://github.com/undergroundwires/privacy.sexy/commit/0fc2ffc1ea36a9248c6a92da85a29f7b04b33796)
* win, linux, mac: fix various typos #349 | [694bf1a](https://github.com/undergroundwires/privacy.sexy/commit/694bf1a74d935531d7cd46891823af1fa58c3c8c)
* Fix script cancellation with new dialog on Linux | [8c17396](https://github.com/undergroundwires/privacy.sexy/commit/8c173962857a39dc0c9e5886cb2af4937e6618e7)
* win: improve disabling protocols | [4ef16ce](https://github.com/undergroundwires/privacy.sexy/commit/4ef16cea56789120cd041412d86b5577cccf0725)
* win: fix Copilot by excluding `r.bing.com` #329 | [66a5688](https://github.com/undergroundwires/privacy.sexy/commit/66a56888a4b3ead1a6bfef0feffa0218535701fe)
* Fix blank window on load on desktop version #348 | [813d820](https://github.com/undergroundwires/privacy.sexy/commit/813d820b85e1b623c50f8e0325ad372bf2f344f9)
* Improve desktop icon quality and generation | [ab25e0a](https://github.com/undergroundwires/privacy.sexy/commit/ab25e0a066be14ea979dafd0f80e1091bd5d33f8)
* win: improve enabling secure connections #175 | [c75df1c](https://github.com/undergroundwires/privacy.sexy/commit/c75df1c8c1151b64cbf014383dea0b748a8c78b3)
* Fix VSCode script issues with added CI/CD tests | [1d7cafc](https://github.com/undergroundwires/privacy.sexy/commit/1d7cafc831dcc339a10646794410dad7096bfe60)
* Fix win execution with whitespace in username #351 | [a334320](https://github.com/undergroundwires/privacy.sexy/commit/a3343205b1196d5a81fd3cee2ae661ce871a7bef)
* Fix misaligned tooltip positions in modal dialogs | [dd71536](https://github.com/undergroundwires/privacy.sexy/commit/dd71536316ec819caeb418b8635d544ac80e58ad)
* Fix Chromium scrollbar-induced layout shifts | [bc4879c](https://github.com/undergroundwires/privacy.sexy/commit/bc4879cfe97becac3c54f6b40780a89464d3b772)
* ci/cd: remove `check-latest` from `setup-node` | [52a4730](https://github.com/undergroundwires/privacy.sexy/commit/52a4730073b8ebfb2ce9d530b44e4a179f5849fe)
* win: categorize and rename network security #131 | [9fd193e](https://github.com/undergroundwires/privacy.sexy/commit/9fd193e676f1f0646898f5130fbfaaf25050b2e3)
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.13.2...0.13.3)
## 0.13.2 (2024-04-15)
* Update documentation for `logo-update.js` script | [4a9b430](https://github.com/undergroundwires/privacy.sexy/commit/4a9b430702bc6082426b50ecc3a06362b5720796)
* win: improve and document removing Phone apps #279 | [8924337](https://github.com/undergroundwires/privacy.sexy/commit/89243371faa5d6aef5fce52b0d54a442143cdd39)
* Fix bottom gap in card expansion panel | [79183d6](https://github.com/undergroundwires/privacy.sexy/commit/79183d64173e588d88bf074d5b50a52a71c2d885)
* ci/cd: Fix macOS Docker build reliability issues | [8a5592f](https://github.com/undergroundwires/privacy.sexy/commit/8a5592f92be4366a806afc9eee9135696a1dd993)
* ci/cd: fix IPv6 timeouts with `force-ipv4` action | [52fadcd](https://github.com/undergroundwires/privacy.sexy/commit/52fadcd6177ed06216be9c67dad57192ae02a4f9)
* ci/cd: bump Node.js environment to 20.x | [59decd1](https://github.com/undergroundwires/privacy.sexy/commit/59decd17e273bada1493eaa855c43cbabf90308f)
* ci/cd: trigger URL checks more, and limit amount | [4fb6302](https://github.com/undergroundwires/privacy.sexy/commit/4fb6302c67f2a3fedff419e8c22872593cf800ef)
* Fix overflow in tree node content on small screens | [557cea3](https://github.com/undergroundwires/privacy.sexy/commit/557cea3f4866dc33236874f5fe4d2d69ee963dae)
* Fix horizontal layout shift after script selection | [bc7e1fa](https://github.com/undergroundwires/privacy.sexy/commit/bc7e1faa1c3f2b61bf2046fdd6d6a4141b484662)
* Fix card header expansion glitch on card collapse | [5d940b5](https://github.com/undergroundwires/privacy.sexy/commit/5d940b57ef2a4c219932cd15201401f8550cfb41)
* Ignore `ResizeObserver` errors in Cypress tests | [4472c28](https://github.com/undergroundwires/privacy.sexy/commit/4472c2852e4b87083bda7979471ab9f377d17a01)
* win: improve and document secret key scripts | [49f22f0](https://github.com/undergroundwires/privacy.sexy/commit/49f22f048f39e7388633c488b5fe59101b831984)
* Fix card arrow not being animated in sync | [7b546c5](https://github.com/undergroundwires/privacy.sexy/commit/7b546c567c4683a37fe94595362f4c2bf92ffd59)
* win: improve Windows feature disablement scripts | [b68711e](https://github.com/undergroundwires/privacy.sexy/commit/b68711ef88982c0ee2b1d41b4452e899821adc64)
* Fix top script menu overflow on small screens | [b7a20d9](https://github.com/undergroundwires/privacy.sexy/commit/b7a20d9d41ea8bcefdd553b87641f3c22b4cde97)
* win: fix Visual Studio remote analysis script #327 | [4142d08](https://github.com/undergroundwires/privacy.sexy/commit/4142d084f64a3b540487ff68b28032977d12006d)
* win: improve firewall docs /w `winget` impact #142 | [ffd647d](https://github.com/undergroundwires/privacy.sexy/commit/ffd647d1529375474b81900cc7bee4c32fbf861f)
* Centralize and use global spacing variables | [ae17200](https://github.com/undergroundwires/privacy.sexy/commit/ae172000a64416e5a3e2b2e32b7846f039f445f0)
* win: improve service revert and docs | [b87b7aa](https://github.com/undergroundwires/privacy.sexy/commit/b87b7aac7d118a23a0d1bfb881e385347de4adb7)
* Bump dependencies to latest, hold ESLint | [f3571ab](https://github.com/undergroundwires/privacy.sexy/commit/f3571abeafdbe1e6d152958fab26de91a9c08bc3)
* Fix inability to tap outside modal on mobile | [cb144ae](https://github.com/undergroundwires/privacy.sexy/commit/cb144ae47273deeb7058d4b1380e480ebccdaf81)
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.13.1...0.13.2)
## 0.13.1 (2024-03-22)
* ci/cd: Fix cross-platform git command compability | [255c51c](https://github.com/undergroundwires/privacy.sexy/commit/255c51c8a0524d3ea8a3b16ffc1b178650525010)
* Fix tooltip falling behind elements on fade out | [1964524](https://github.com/undergroundwires/privacy.sexy/commit/19645248ab7bc78dc872fa176c1a3650d7d6d644)
* Improve VSCode detection in `configure_vscode.py` | [98845e6](https://github.com/undergroundwires/privacy.sexy/commit/98845e6caee168db131aaf0736533e450827a52c)
* Bump TypeScript to 5.3 with `verbatimModuleSyntax` | [a721e82](https://github.com/undergroundwires/privacy.sexy/commit/a721e82a4fb603c0732ccfdffc87396c2a01363e)
* Migrate to Vite 5 and adjust configurations | [4ac1425](https://github.com/undergroundwires/privacy.sexy/commit/4ac1425f76079352268c488f3ff607d1fdc1beb2)
* win: improve and unify service start/stop logic | [adc2089](https://github.com/undergroundwires/privacy.sexy/commit/adc20898873d50a8873ffc74c48257e69a45d367)
* Upgrade vitest to v1 and fix test definitions | [e721885](https://github.com/undergroundwires/privacy.sexy/commit/e7218850ba62a7bebaf4768b13e46cba0dedd906)
* Improve URL checks to reduce false-negatives | [5abf8ff](https://github.com/undergroundwires/privacy.sexy/commit/5abf8ff216a1da737fd489864eeee880f78d6601)
* win: improve OneDrive data deletion safety | [5eff3a0](https://github.com/undergroundwires/privacy.sexy/commit/5eff3a04886d0d23a6e4c13a0178bb247105c5cb)
* Bump Electron to latest and use native ESM | [840adf9](https://github.com/undergroundwires/privacy.sexy/commit/840adf9429ed47f9e88c05e90f1d3ab930c2dfc4)
* Fix tooltip styling inconsistency | [ec34ac1](https://github.com/undergroundwires/privacy.sexy/commit/ec34ac1124e8b8ae53bf31a4dbdc88bb078b3d4e)
* win: fix VSCode manual update switch script #312 | [b71ad79](https://github.com/undergroundwires/privacy.sexy/commit/b71ad797a3af0db45143249903cb5e178692de7c)
* mac, linux, win: fix dead URLs and improve docs | [abec9de](https://github.com/undergroundwires/privacy.sexy/commit/abec9def075d82fdaee9663ef8fe1a488911f45b)
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.13.0...0.13.1)
## 0.13.0 (2024-02-11)
* win: add disabling clipboard features #251, #247 | [c6ebba8](https://github.com/undergroundwires/privacy.sexy/commit/c6ebba85fb1b362be0d81d3078f19db71e0528b2)
* win: improve search privacy scripts #117 | [541f9aa](https://github.com/undergroundwires/privacy.sexy/commit/541f9aa5ee1b5f4885063b65beaf6cd873f0d786)
* win: add disabling Windows Copilot #263, #266 | [cd42550](https://github.com/undergroundwires/privacy.sexy/commit/cd425502ae882bba9642dc2171c2b5771946b5a9)
* win: add Dropbox telemetry blocking #125, #118 | [10829d6](https://github.com/undergroundwires/privacy.sexy/commit/10829d65aa3fb0df937bb8829244e6290bb748c7)
* Improve selection type documentation | [7af8daa](https://github.com/undergroundwires/privacy.sexy/commit/7af8daa3411b24efb6385c7876a49bd372753f38)
* Expand script names to take full available width | [d277139](https://github.com/undergroundwires/privacy.sexy/commit/d277139dd50eeb4e4057b0a7d8fc4ac2d70785de)
* Limit tooltip width for improved readability | [6ab6dac](https://github.com/undergroundwires/privacy.sexy/commit/6ab6dacd1be2d7bf1863b07b121d86f2a379ac67)
* Add markdown support for script/category names | [a5ffed4](https://github.com/undergroundwires/privacy.sexy/commit/a5ffed4cd60d9d058d5374145c1176b10fad1660)
* Normalize and improve font sizes | [4da306b](https://github.com/undergroundwires/privacy.sexy/commit/4da306b9f79b0bb7a64bb197fb246258cf435b8d)
* Change 'revert' button to title case | [937f459](https://github.com/undergroundwires/privacy.sexy/commit/937f4593d1a91081ab6b1bcb8f85d03879d7cf07)
* Remove playful emojis (🍑🍆) | [aa4205f](https://github.com/undergroundwires/privacy.sexy/commit/aa4205ff7af7d05cfb5e82bf541b521d49bbd1c8)
* Improve UI code styling for all platforms | [311fcb1](https://github.com/undergroundwires/privacy.sexy/commit/311fcb18133d1343f6a9ae5bd7a25795a1d12c49)
* Render bracket references as superscript text | [b9c89b7](https://github.com/undergroundwires/privacy.sexy/commit/b9c89b701fc77d20dcc706419a8659ad156c4fc2)
* Change slogan and refactor project info naming | [a54e164](https://github.com/undergroundwires/privacy.sexy/commit/a54e16488ce32219bcf811b5da85f06584b293fb)
* Add 'Revert All Selection' feature #68 | [55fa7ea](https://github.com/undergroundwires/privacy.sexy/commit/55fa7eae71031357d6f03f0d349a09cd446270d3)
* win, mac, linux: add privacy.sexy cleanup scripts | [63366a4](https://github.com/undergroundwires/privacy.sexy/commit/63366a4ec2533a376849d692211e9972b56ab4a8)
* Extend search by including documentation content | [6142f3a](https://github.com/undergroundwires/privacy.sexy/commit/6142f3a2973d20493f784f323f3be57fa8deaeef)
* Remove 'preview' label from Linux options | [ebd8285](https://github.com/undergroundwires/privacy.sexy/commit/ebd82853ddc56f1cc2fc9be3fe0b3001b07f0186)
* Change fonts for improved readability | [d5bbc32](https://github.com/undergroundwires/privacy.sexy/commit/d5bbc321f902dc60618ffdfda0d583a4a433f7af)
* Apply global styles for visual consistency | [faa7a38](https://github.com/undergroundwires/privacy.sexy/commit/faa7a38a7d16390f27e4a3e51017b81665cf85ca)
* Add UI animations for expand/collapse actions | [fb08f03](https://github.com/undergroundwires/privacy.sexy/commit/fb08f037651e1a7d453b9a6af724cbccecc5b903)
* win: relocate service disabling and improve docs | [894687c](https://github.com/undergroundwires/privacy.sexy/commit/894687c0e0375a24f40bcd720ea69c9b2aa62a58)
* win: add host blocking category #26 | [17152c8](https://github.com/undergroundwires/privacy.sexy/commit/17152c84dc639e75560998a6feddfd46e0f713ce)
* Update meta title and description | [c7fa4b6](https://github.com/undergroundwires/privacy.sexy/commit/c7fa4b6d020ac6fd3bf72bb4e57022dffb1ba921)
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.12.10...0.13.0)
## 0.12.10 (2024-01-17)
* Fix CSP for Vue, Ace, Vite, Safari compatibility | [940febc](https://github.com/undergroundwires/privacy.sexy/commit/940febc3e80cfd0c01b5cc8282ebaab6b024d1b5)
* Improve security by isolating code execution more | [efa05f4](https://github.com/undergroundwires/privacy.sexy/commit/efa05f42bc53c44a352152b7c272bc0bda363070)
* Fix unresponsive circle icon in revert button | [645c333](https://github.com/undergroundwires/privacy.sexy/commit/645c33378769969c525a1552c65f8d0005e25fcf)
* Improve documentation for contribution guidelines | [fc9dd23](https://github.com/undergroundwires/privacy.sexy/commit/fc9dd234e9c749247f42289432ebb92dbe0a5f64)
* Bump Node.js environment to 18.x | [2f06043](https://github.com/undergroundwires/privacy.sexy/commit/2f0604355988a421690bb275375c3df280af7ee6)
* Fix button inconsistencies and macOS layout shifts | [86fde6d](https://github.com/undergroundwires/privacy.sexy/commit/86fde6d7dc61bbeeb3088cd24e37451181cc4e01)
* win: fix language dependent delete script #149 | [8f4b34f](https://github.com/undergroundwires/privacy.sexy/commit/8f4b34f8f156476f56fb7dde8e7c762f4455518b)
* Improve desktop script runs with timestamps & logs | [cdc32d1](https://github.com/undergroundwires/privacy.sexy/commit/cdc32d1f12c938966238c9569c91b64b23cd6f26)
* win: improve store app docs and add research #279 | [fac72ed](https://github.com/undergroundwires/privacy.sexy/commit/fac72edd551264320ed97194e7ecb3fcc34139f7)
* Fix handling special chars in script paths | [40f5eb8](https://github.com/undergroundwires/privacy.sexy/commit/40f5eb8334b27e958eee63e2141ded7d5861d960)
* Fix macOS detection in desktop app and Chromium | [dc30825](https://github.com/undergroundwires/privacy.sexy/commit/dc30825232a1355a325e364c8cd9fde78ffa3b1a)
* Bump ESLint Typescript dependencies to latest | [bf7fb07](https://github.com/undergroundwires/privacy.sexy/commit/bf7fb0732c52745521c1a89b963bdbf3394d9e63)
* Fix script deletion during execution on desktop | [c84a1bb](https://github.com/undergroundwires/privacy.sexy/commit/c84a1bb74ccb7a53bd493684b63a9e04f40e0b8b)
* Fix script execution for Linux VSCode development | [3b1a89c](https://github.com/undergroundwires/privacy.sexy/commit/3b1a89ce863c18c32be7d0b22dba566f692d81d1)
* Fix touch, cursor and accessibility in slider | [7285842](https://github.com/undergroundwires/privacy.sexy/commit/728584240cae6b3857abca4d3ddaaa7f6bb4a66e)
* Fix invisible script execution on Windows #264 | [b404a91](https://github.com/undergroundwires/privacy.sexy/commit/b404a91ada509e19a287d026d55db0035ff6233b)
* win: add missing extension apps, improve docs #279 | [da4be50](https://github.com/undergroundwires/privacy.sexy/commit/da4be500da7b0b5897a8b3e0525d9e50c9159fe0)
* Show native save dialogs in desktop app #50, #264 | [c546a33](https://github.com/undergroundwires/privacy.sexy/commit/c546a33eff7506550c7bcf03bb1f227a7c091816)
* Show save/execution error dialogs on desktop #264 | [e09db0f](https://github.com/undergroundwires/privacy.sexy/commit/e09db0f1bd73503204d8e5375a9cfe693f174a57)
* Add Windows save instructions UI and fix URL #296 | [756c736](https://github.com/undergroundwires/privacy.sexy/commit/756c736e21d713b8d2651cf2a9d7cf0678badde0)
* Add AD detection on desktop app #264, #304 | [f03fc24](https://github.com/undergroundwires/privacy.sexy/commit/f03fc2409832ddf904bc6bd4e19274a8d40745dc)
* Improve script error dialogs #304 | [6ada8d4](https://github.com/undergroundwires/privacy.sexy/commit/6ada8d425c4a7df88490756187c84b5c57ed1dcc)
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.12.9...0.12.10)
## 0.12.9 (2023-12-16)
* win: improve docs and category of jump lists #146 | [40ae8a8](https://github.com/undergroundwires/privacy.sexy/commit/40ae8a8addaeb834ee26eabd330fda5cbb495324)
* mac: improve clearing privacy permissions | [5a7d7d8](https://github.com/undergroundwires/privacy.sexy/commit/5a7d7d88ff2f3e8862b18c94d062f692ee4b690b)
* win: fix logic for terminating processes | [807ae6a](https://github.com/undergroundwires/privacy.sexy/commit/807ae6a8f8ca724d781169f3ecb40f43ccd3fe10)
* win: improve documentation for "Get Help" app #280 | [8f5d7ed](https://github.com/undergroundwires/privacy.sexy/commit/8f5d7ed3cfa57f66dded9b72374006c9b6df2ce9)
* Centralize log file and refactor desktop logging | [08dbfea](https://github.com/undergroundwires/privacy.sexy/commit/08dbfead7ca7b55fe85f7dded01f2d4b88906c72)
* win: fix revert and improve docs for SAM enum #255 | [25e23c8](https://github.com/undergroundwires/privacy.sexy/commit/25e23c89c3f86897d5661a24a774997c924d3b2d)
* Improve security and reliability of macOS updates | [4765752](https://github.com/undergroundwires/privacy.sexy/commit/4765752ee3a36301b3d97317c570432424de8460)
* win: fix Win 11 Windows Security app removal #195 | [daa6230](https://github.com/undergroundwires/privacy.sexy/commit/daa6230fc96f2cf7210bc8c165106c0d5544e5fb)
* Improve security and privacy with strict meta tags | [ba5b29a](https://github.com/undergroundwires/privacy.sexy/commit/ba5b29a35dd7665aeea430aec4aaa8ff5ca811de)
* win: document and discourage admin shares #249 | [e747ee5](https://github.com/undergroundwires/privacy.sexy/commit/e747ee5cbc7cf5f0fe28a87fe7d02457d777373e)
* win: discourage XboxIdentityProvider #64, #79 #181 | [c72f9f5](https://github.com/undergroundwires/privacy.sexy/commit/c72f9f501680c1d880a0b560d02451a9e31063b4)
* win: improve disabling update healing #272 | [47b4823](https://github.com/undergroundwires/privacy.sexy/commit/47b4823bc5e487188b12cbea67db2525260af497)
* Fix tooltip overflow on smaller screens | [916c9d6](https://github.com/undergroundwires/privacy.sexy/commit/916c9d62d9fce27c3cd3feaf90c66df584d4f04a)
* Fix touch state not being activated in iOS Safari | [a985127](https://github.com/undergroundwires/privacy.sexy/commit/a9851272ae14eb1b374767b0eed3eb68e6dd1560)
* Fix tree view alignment and padding issues | [15134ea](https://github.com/undergroundwires/privacy.sexy/commit/15134ea04bc46e8cb13977d75b788f5ff71c800e)
* win: improve disabling of Application Experience | [fe3de49](https://github.com/undergroundwires/privacy.sexy/commit/fe3de498c8a1394efd6517d436797a08f938bb57)
* Fix OS switching not working on tree view UI | [3457fe1](https://github.com/undergroundwires/privacy.sexy/commit/3457fe18cf8193883f45b50ecbc9638c91ace2fb)
* Fix touch-enabled Chromium highlight on tree nodes | [2063397](https://github.com/undergroundwires/privacy.sexy/commit/20633972e9b56bdc102357129e74df30a95cefa9)
* win: add scripts to postpone auto-updates #272 | [e95b2ba](https://github.com/undergroundwires/privacy.sexy/commit/e95b2ba2179e40c0033a51b0087871dbfdc32d78)
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.12.8...0.12.9)
## 0.12.8 (2023-11-27)
* Remove duplicated `index.html` file | [aab0f7e](https://github.com/undergroundwires/privacy.sexy/commit/aab0f7ea4680f377c610066bd0e99011eed8b506)
* Refactor DI for simplicity and type safety | [7770a9b](https://github.com/undergroundwires/privacy.sexy/commit/7770a9b5211d7208cfb2bfa5f737d46dc90b7946)
* Refactor user selection state handling using hook | [58cd551](https://github.com/undergroundwires/privacy.sexy/commit/58cd551a304a03e42637e6858982f8c5dfd9f598)
* Refactor watch sources for reliability | [7ab16ec](https://github.com/undergroundwires/privacy.sexy/commit/7ab16ecccb31b2d54e5b634520a8246fbbc248c1)
* Refactor to enforce strictNullChecks | [949fac1](https://github.com/undergroundwires/privacy.sexy/commit/949fac1a7cbc962ed63058e6a896695cfb4d35c8)
* Fix icon tooltip alignment on instructions modal | [bd383ed](https://github.com/undergroundwires/privacy.sexy/commit/bd383ed273ca95c10ea1cce765c0aa6836ec508c)
* Fix mobile layout overflow caused by tooltips | [e541a35](https://github.com/undergroundwires/privacy.sexy/commit/e541a35e86c0eff83f84dd002b46de7c55ebbcac)
* win: improve disabling of scheduled tasks | [3864f04](https://github.com/undergroundwires/privacy.sexy/commit/3864f042180f62afe469fdfe36010b018f84f4b3)
* Fix card list UI layout shifts (jumps) on load | [bf3426f](https://github.com/undergroundwires/privacy.sexy/commit/bf3426f91b6b7dbcad58d58507222559a8d14242)
* Refactor to Vue 3 recommended ESLint rules | [4531645](https://github.com/undergroundwires/privacy.sexy/commit/4531645b4c0c5143f15240652368bb9b9ddb48a4)
* Fix code highlighting and optimize category select | [cb42f11](https://github.com/undergroundwires/privacy.sexy/commit/cb42f11b9785e74719338a0a80a50d81dfccb4b6)
* Fix layout jumps/shifts and overflow on modals | [e299d40](https://github.com/undergroundwires/privacy.sexy/commit/e299d40fa1d71d921d4dac37e469fe299c9da3af)
* win: fix and improve Store app categorization #190 | [094dbb0](https://github.com/undergroundwires/privacy.sexy/commit/094dbb01b83bce9925fafab778b922f64390c2be)
* win: fix persistent update disabling /w tasks #272 | [dee3279](https://github.com/undergroundwires/privacy.sexy/commit/dee3279f85c99a9c62201a093b1afa41ec2412ec)
* win: discourage IntelliCode disabling #267, #286 | [7f7a84e](https://github.com/undergroundwires/privacy.sexy/commit/7f7a84e3ba259fade22d4838563d16129a1585e6)
* Fix spacing in documentation for readability | [1442f62](https://github.com/undergroundwires/privacy.sexy/commit/1442f626335e30e3a8d74e4e13e561c41f073ef8)
* win: fix system app removal affecting updates #287 | [7c632f7](https://github.com/undergroundwires/privacy.sexy/commit/7c632f738853b32fd90952bb4ca1ac924f962eb0)
* Fix rendering of inline code blocks for docs | [9845a7c](https://github.com/undergroundwires/privacy.sexy/commit/9845a7cd68a9920c96da739b58238bb1fdb1251d)
* linux: fix Firefox settings not reverting #282 | [bcad357](https://github.com/undergroundwires/privacy.sexy/commit/bcad357017d9f29ce77e706ca943107dd9caefb6)
* Fix incorrect URL rendering in documentation texts | [d328f08](https://github.com/undergroundwires/privacy.sexy/commit/d328f0895244d998e885ad8df335b6444b9ac66b)
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.12.7...0.12.8)
## 0.12.7 (2023-11-07)
* Add winget download instructions | [b2ffc90](https://github.com/undergroundwires/privacy.sexy/commit/b2ffc90da70367b9e65c82556e8f440f865ceb98)
* Fix unresponsive copy button on instructions modal | [8ccaec7](https://github.com/undergroundwires/privacy.sexy/commit/8ccaec7af6ea3ecfd46bab5c13b90f71d55e32c1)
* Fix tree node check states not being updated | [af7219f](https://github.com/undergroundwires/privacy.sexy/commit/af7219f6e12ab4a65ce07190f691cf3234e87e35)
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.12.6...0.12.7)
## 0.12.6 (2023-11-03)
* Bump dependencies to latest | [25d7f7b](https://github.com/undergroundwires/privacy.sexy/commit/25d7f7b2a479e51e092881cc2751e67a7d3f179f)
* win: improve system app uninstall cleanup #73 | [dbe3c5c](https://github.com/undergroundwires/privacy.sexy/commit/dbe3c5cfb91ba8a1657838b69117858843c8fbc8)
* win: improve system app uninstall /w fallback #260 | [98a26f9](https://github.com/undergroundwires/privacy.sexy/commit/98a26f9ae47af2668aa53f39d1768983036048ce)
* Improve performance of rendering during search | [79b46bf](https://github.com/undergroundwires/privacy.sexy/commit/79b46bf21004d96d31551439e5db5d698a3f71f3)
* Fix YAML error for site release in CI/CD | [237d994](https://github.com/undergroundwires/privacy.sexy/commit/237d9944f900f5172366868d75219224ff0542b0)
* win: fix Microsoft Advertising app removal #200 | [e40b9a3](https://github.com/undergroundwires/privacy.sexy/commit/e40b9a3cf53c341f2e84023a9f0e9680ac08f3fa)
* win: improve directory cleanup security | [060e789](https://github.com/undergroundwires/privacy.sexy/commit/060e7896624309aebd25e8b190c127282de177e8)
* Centralize Electron entry file path configuration | [d6da406](https://github.com/undergroundwires/privacy.sexy/commit/d6da406c61e5b9f5408851d1302d6d7398157a2e)
* win: prevent updates from reinstalling apps #260 | [8570b02](https://github.com/undergroundwires/privacy.sexy/commit/8570b02dde14ffad64863f614682c3fc1f87b6c2)
* win: improve script environment robustness #221 | [dfd4451](https://github.com/undergroundwires/privacy.sexy/commit/dfd44515613f38abe5a806bda36f44e7b715b50b)
* Fix compiler failing with nested `with` expression | [80821fc](https://github.com/undergroundwires/privacy.sexy/commit/80821fca0769e5fd2c6338918fbdcea12fbe83d2)
* win: improve soft file/app delete security #260 | [f4a74f0](https://github.com/undergroundwires/privacy.sexy/commit/f4a74f058db9b5bcbcbe438785db5ec88ecc1657)
* Fix incorrect tooltip position after window resize | [f8e5f1a](https://github.com/undergroundwires/privacy.sexy/commit/f8e5f1a5a2afa1f18567e6d965359b6a1f082367)
* linux: fix string formatting of Firefox configs | [e775d68](https://github.com/undergroundwires/privacy.sexy/commit/e775d68a9b4a5f9e893ff0e3500dade036185193)
* win: improve file delete | [e72c1c1](https://github.com/undergroundwires/privacy.sexy/commit/e72c1c13ea2d73ebfc7a8da5a21254fdfc0e5b59)
* win: change system app removal to hard delete #260 | [77123d8](https://github.com/undergroundwires/privacy.sexy/commit/77123d8c929d23676a9cb21d7b697703fd1b6e82)
* Improve UI performance by optimizing reactivity | [4995e49](https://github.com/undergroundwires/privacy.sexy/commit/4995e49c469211404dac9fcb79b75eb121f80bce)
* Migrate to Vue 3.0 #230 | [ca81f68](https://github.com/undergroundwires/privacy.sexy/commit/ca81f68ff1c3bbe5b22981096ae9220b0b5851c7)
* win, linux: unify & improve Firefox clean-up #273 | [0466b86](https://github.com/undergroundwires/privacy.sexy/commit/0466b86f1013341c966a9bbf6513990337b16598)
* win: fix store revert for multiple installs #260 | [5bb13e3](https://github.com/undergroundwires/privacy.sexy/commit/5bb13e34f8de2e2a7ba943ff72b12c0569435e62)
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.12.5...0.12.6)
## 0.12.5 (2023-10-13) ## 0.12.5 (2023-10-13)
* Fix Docker build and improve checks #220 | [7669985](https://github.com/undergroundwires/privacy.sexy/commit/7669985f8e1446e726a95626ecf35b3ce6b60a16) * Fix Docker build and improve checks #220 | [7669985](https://github.com/undergroundwires/privacy.sexy/commit/7669985f8e1446e726a95626ecf35b3ce6b60a16)

View File

@@ -1,6 +1,6 @@
# Contributing # Contributing
Love your input ❤️! Contributing to this project should be as easy and transparent as possible, whether it's: Love your input! Contributing to this project should be as easy and transparent as possible, whether it's:
- reporting a bug, - reporting a bug,
- discussing the current state of the code, - discussing the current state of the code,
@@ -16,7 +16,7 @@ Your pull requests are actively welcomed. We collaborate using [GitHub flow](htt
The steps: The steps:
1. Fork the repository and create your branch from `master`. 1. Fork the repo and create your branch from master.
2. If you've added code that requires testing, add tests. See [tests.md](./docs/tests.md). 2. If you've added code that requires testing, add tests. See [tests.md](./docs/tests.md).
3. If you've done a major change, update the documentation. See [docs/](./docs/). 3. If you've done a major change, update the documentation. See [docs/](./docs/).
4. Ensure the test suite passes. See [development.md | Testing](./docs/development.md#testing) for commands. 4. Ensure the test suite passes. See [development.md | Testing](./docs/development.md#testing) for commands.
@@ -37,44 +37,15 @@ Automated pipelines will run to control your PR and they will publish your code
## Extend scripts ## Extend scripts
If you're interested in adding new scripts to privacy.sexy: Here's quick information for you who want to add more scripts.
1. Read [guidelines for a good script](./docs/script-guidelines.md) You have two alternatives:
2. Choose one of two ways to contribute:
1. [Create an issue](https://github.com/undergroundwires/privacy.sexy/issues/new/choose) requesting the addition of a new script. This allows other contributors to develop and add it for you. This will take longer time.
2. Submit a pull request with your script. This is the faster route to seeing your script included in the project. Add your scripts to the appropriate OS directory in the [collections](src/application/collections/) (for syntax guidance, see [collection-files.md](docs/collection-files.md)) folder, and follow the [pull request process](#pull-request-process).
## Commit conventions 1. [Create an issue](https://github.com/undergroundwires/privacy.sexy/issues/new/choose) and ask for someone else to add the script for you.
2. Or send a PR yourself. This would make it faster to get your code into the project. You need to add scripts to related OS in [collections](src/application/collections/) folder. Then you'd sent a pull request, see [pull request process](#pull-request-process).
- Adhere to the 50/72 rule: - 📖 If you're unsure about the syntax, check [collection-files.md](docs/collection-files.md).
- Commit titles should not exceed 50 characters. - 📖 If you wish to use templates, use [templating.md](./docs/templating.md).
- Limit description lines to 72 characters, except for code blocks or inline codes.
- Avoid including delta (such as `git diff` information) or a list of changed files in the commit message. This information is redundant as it's already part of the commit.
- Focus on explaining the WHY and HOW of the changes, rather than WHAT changes are.
- Begin the commit message with a concise summary of what the commit accomplishes.
- Use imperative language in the commit title. For example, use "add" instead of "added".
- Commit prefixes:
- Prefix bug fixes with `fix:` or `Fix ...`.
- For commits affecting scripts of specific operating systems:
- Prefix the commit title with an OS-specific tag such as `win:` for Windows scripts, `mac:` for macOS scripts, and `linux:` for Linux scripts.
- Combine prefixes for commits affecting more than one operating system, e.g., `win, mac: ...`.
## Versioning
We base versioning on the release's content rather than strictly following semantic versioning.
There are two main types of releases:
1. **Patch Releases:** These focus on minor UI improvements, bug fixes, refactorings, dependency updates, and documentation updates. For scripts, they involve adjusting recommendation levels, enhancing functionality, and dividing scripts for more precise control. Patch releases may ship minor feature additions if they are essential for fixing a bug. For these updates, we increment the patch number in the `MAJOR.MINOR.PATCH`.
2. **Feature Releases:** These releases bring significant updates that change how users interact with privacy.sexy. They include major UI enhancements, the introduction of new scripts, and features. For these updates, we increment the minor number in the `MAJOR.MINOR.PATCH`.
Maintainers tag specific commits with a version number to trigger a release, and [bump-everywhere](https://github.com/undergroundwires/bump-everywhere) automates the release process including updating version numbers throughout the project.
## Refactoring
Opportunistic refactoring is welcome. If you're adding a feature or fixing a bug, feel free to also clean up and optimize the related code. Your contributions should leave the code in a better state than when you found it.
## License ## License
By contributing to this project, you agree that your contributions are licensed under the [GNU Affero General Public License](./LICENSE) as currently specified. Additionally, you expressly consent to the project maintainers having full authority to modify the licensing terms or relicense your contributions under different terms in the future. By contributing, you agree that your [GNU General Public License v3.0](./LICENSE) will be the license for your contributions.

View File

@@ -1,6 +1,6 @@
# privacy.sexy — Privacy is sexy # privacy.sexy — Now you have the choice
> Enforce privacy & security best-practices on Windows, macOS and Linux, because privacy is sexy. > Enforce privacy & security best-practices on Windows, macOS and Linux, because privacy is sexy 🍑🍆
<!-- markdownlint-disable MD033 --> <!-- markdownlint-disable MD033 -->
<p align="center"> <p align="center">
@@ -60,8 +60,8 @@
<br /> <br />
<a href="https://github.com/undergroundwires/privacy.sexy/actions/workflows/checks.quality.yaml" target="_blank" rel="noopener noreferrer"> <a href="https://github.com/undergroundwires/privacy.sexy/actions/workflows/checks.quality.yaml" target="_blank" rel="noopener noreferrer">
<img <img
alt="Status of quality checks" alt="Quality checks status"
src="https://github.com/undergroundwires/privacy.sexy/workflows/checks.quality/badge.svg" src="https://github.com/undergroundwires/privacy.sexy/workflows/quality-checks/badge.svg"
/> />
</a> </a>
<a href="https://github.com/undergroundwires/privacy.sexy/actions/workflows/checks.build.yaml" target="_blank" rel="noopener noreferrer"> <a href="https://github.com/undergroundwires/privacy.sexy/actions/workflows/checks.build.yaml" target="_blank" rel="noopener noreferrer">
@@ -122,14 +122,11 @@
## Get started ## Get started
- 🌍️ **Online**: [https://privacy.sexy](https://privacy.sexy). - 🌍️ **Online**: [https://privacy.sexy](https://privacy.sexy).
- 🖥️ **Offline**: Download directly for: [Windows](https://github.com/undergroundwires/privacy.sexy/releases/download/0.13.6/privacy.sexy-Setup-0.13.6.exe), [macOS](https://github.com/undergroundwires/privacy.sexy/releases/download/0.13.6/privacy.sexy-0.13.6.dmg), [Linux](https://github.com/undergroundwires/privacy.sexy/releases/download/0.13.6/privacy.sexy-0.13.6.AppImage). For more options, see [here](#additional-install-options). - 🖥️ **Offline**: Download directly for: [Windows](https://github.com/undergroundwires/privacy.sexy/releases/download/0.12.5/privacy.sexy-Setup-0.12.5.exe), [macOS](https://github.com/undergroundwires/privacy.sexy/releases/download/0.12.5/privacy.sexy-0.12.5.dmg), [Linux](https://github.com/undergroundwires/privacy.sexy/releases/download/0.12.5/privacy.sexy-0.12.5.AppImage). For more options, see [here](#additional-install-options).
See also: Online version does not require to run any software on your computer. Offline version has more functions such as running the scripts directly.
- [Desktop vs. Web Features](./docs/desktop/desktop-vs-web-features.md): Differences and unique aspects of desktop and web versions. 💡 You should apply your configuration from time to time (more than once). It would strengthen your privacy and security control because privacy.sexy and its scripts get better and stronger in every new version.
- [System Requirements](./docs/desktop/system-requirements.md): Hardware and software requirements for the desktop version.
💡 Regularly applying your configuration with privacy.sexy is recommended, especially after each new release and major operating system updates. Each version updates scripts to enhance stability, privacy, and security.
[![privacy.sexy application](img/screenshot.png?raw=true )](https://privacy.sexy) [![privacy.sexy application](img/screenshot.png?raw=true )](https://privacy.sexy)
@@ -140,7 +137,6 @@ See also:
- **Transparent**. Have full visibility into what the tweaks do as you enable them. - **Transparent**. Have full visibility into what the tweaks do as you enable them.
- **Reversible**. Revert if something feels wrong. - **Reversible**. Revert if something feels wrong.
- **Accessible**. No need to run any compiled software on your computer with web version. - **Accessible**. No need to run any compiled software on your computer with web version.
- **Secure**: Security is a top priority at privacy.sexy with [comprehensive safeguards](./SECURITY.md#security-practices) in place.
- **Open**. What you see as code in this repository is what you get. The application itself, its infrastructure and deployments are open-source and automated thanks to [bump-everywhere](https://github.com/undergroundwires/bump-everywhere). - **Open**. What you see as code in this repository is what you get. The application itself, its infrastructure and deployments are open-source and automated thanks to [bump-everywhere](https://github.com/undergroundwires/bump-everywhere).
- **Tested**. A lot of tests. Automated and manual. Community-testing and verification. Stability improvements comes before new features. - **Tested**. A lot of tests. Automated and manual. Community-testing and verification. Stability improvements comes before new features.
- **Extensible**. Effortlessly [extend scripts](./CONTRIBUTING.md#extend-scripts) with a custom designed [templating language](./docs/templating.md). - **Extensible**. Effortlessly [extend scripts](./CONTRIBUTING.md#extend-scripts) with a custom designed [templating language](./docs/templating.md).
@@ -157,21 +153,12 @@ See also:
## Additional Install Options ## Additional Install Options
- Check the [releases page](https://github.com/undergroundwires/privacy.sexy/releases) for all available versions. - Check the [releases page](https://github.com/undergroundwires/privacy.sexy/releases) for all available versions.
- Other unofficial channels (not maintained by privacy.sexy) for Windows include: - Using [Scoop](https://scoop.sh/#/apps?q=privacy.sexy&s=2&d=1&o=true) package manager on Windows:
- [Scoop 🥄](https://scoop.sh/#/apps?q=privacy.sexy&s=2&d=1&o=true) (latest version):
```powershell ```powershell
scoop bucket add extras scoop bucket add extras
scoop install privacy.sexy scoop install privacy.sexy
``` ```
- [winget 🪟](https://winget.run/pkg/undergroundwires/privacy.sexy) (may be outdated):
```powershell
winget install -e --id undergroundwires.privacy.sexy
```
With winget, updates require manual submission; the auto-update feature within privacy.sexy will notify you of new releases post-installation.
## Development ## Development
@@ -183,10 +170,4 @@ Check [architecture.md](./docs/architecture.md) for an overview of design and ho
## Security ## Security
Security is a top priority at privacy.sexy. Security is a top priority at privacy.sexy. An extensive commitment to security verification ensures this priority. For any security concerns or vulnerabilities, please consult the [Security Policy](./SECURITY.md).
An extensive commitment to security verification ensures this priority.
For any security concerns or vulnerabilities, please consult the [Security Policy](./SECURITY.md).
## Supporters
[![Supporters appreciation banner showing the supporters](https://undergroundwires.dev/img/supporters.jpg)](https://undergroundwires.dev/supporters)

View File

@@ -1,7 +1,6 @@
# Security Policy # Security Policy
Security is a top priority at privacy.sexy. privacy.sexy takes security seriously. Commitment is made to address all security issues with urgency. Responsible reporting of any discovered vulnerabilities in the project is highly encouraged.
Please report any discovered vulnerabilities responsibly.
## Reporting a Vulnerability ## Reporting a Vulnerability
@@ -12,65 +11,20 @@ Efforts to responsibly disclose findings are greatly appreciated. To report a se
## Security Report Handling ## Security Report Handling
Upon receiving a security report, the process involves: Upon receipt of a security report, the following actions will be taken:
- Confirming the report and identifying affected components. - The report will be confirmed, identifying the affected components.
- Assessing the impact and severity of the issue. - The impact and severity of the issue will be assessed.
- Fixing the vulnerability and planning a release to address it. - Work on a fix and plan a release to address the vulnerability will be initiated.
- Keeping the reporter informed about progress. - The reporter will be kept updated about the progress.
## Security Practices ## Testing
### Application Security Regular and extensive testing is conducted to ensure robust security in the project. Information about testing practices can be found in the [Testing Documentation](./docs/tests.md).
privacy.sexy adopts a defense in depth strategy to protect users on multiple layers:
- **Link Protection:**
privacy.sexy ensures each external link has special attributes for your privacy and security.
These attributes block the new site from accessing the privacy.sexy page, increasing your online safety and privacy.
- **Content Security Policies (CSP):**
privacy.sexy actively follows security guidelines from the Open Web Application Security Project (OWASP) at strictest level.
This approach protects against attacks like Cross Site Scripting (XSS) and data injection.
- **Host System Access Control:**
The desktop application segregates and isolates code sections based on their access levels through sandboxing.
This provides a critical defense mechanism, prevents attackers from introducing harmful code into the app, known as injection attacks.
- **Auditing and Transparency:**
The desktop application improves security and transparency by logging application activities and retaining files of executed scripts
This facilitates detailed auditability and effective troubleshooting, contributing to the integrity and reliability of the application.
Recognizing that some users prefer not to keep these records, privacy.sexy provides specialized scripts for deletion of these logs.
- **Privilege Management:**
The desktop application operates without persistent administrative or `sudo` privileges, reinforcing its security posture. It requests
elevation of privileges for system modifications with explicit user consent and logs every action taken with high privileges. This
approach actively minimizes potential security risks by limiting privileged operations and aligning with the principle of least privilege.
- **Secure Script Execution/Storage:**
- **Antivirus scans:**
Before executing any script, the desktop application stores a copy to allow antivirus software to perform scans.
This step allows confirming that the scripts are secure and safe to use.
- **Tamper protection:**
The application incorporates integrity checks for tamper protection.
If the script file differs from the user's selected script, the application will not execute or save the script, ensuring the processing
of authentic scripts.
This safeguards against any unwanted modifications.
- **Clean-up:**
Recognizing that some users prefer not to keep these records, privacy.sexy provides specialized scripts for deletion of these scripts.
This allows users to maintain their privacy by removing traces of their usage patterns or script preferences.
### Update Security and Integrity
privacy.sexy benefits from automated update processes including security tests. Automated deployments from source code ensure immediate and secure updates, mirroring the latest source code. This aligns the deployed application with the expected source code, enhancing transparency and trust. For more details, see [CI/CD Documentation](./docs/ci-cd.md).
Every desktop update undergoes a thorough verification process. Updates are cryptographically signed to ensure authenticity and integrity, preventing tampered versions from reaching your device. Version checks are conducted to prevent downgrade attacks.
### Testing
privacy.sexy's testing approach includes a mix of automated and community-driven tests.
Details on testing practices are available in the [Testing Documentation](./docs/tests.md).
## Support ## Support
For help or any questions, [submit a GitHub issue](https://github.com/undergroundwires/privacy.sexy/issues/new/choose). Addressing security concerns is a priority, and we ensure the necessary support. For additional assistance or any unanswered questions, [submit a GitHub issue](https://github.com/undergroundwires/privacy.sexy/issues/new/choose). Security concerns are a priority, and necessary support to address them is assured.
Support privacy.sexy's commitment to security by [making a donation ❤️](https://github.com/sponsors/undergroundwires). Your contributions aid in maintaining and enhancing the project's security features.
--- ---

5
build/README.md Normal file
View File

@@ -0,0 +1,5 @@
# build
This folder contains files that are used by Electron to serve the desktop version.
Icons are created from the main logo file and should not be changed manually, see [related documentation](./../img/README.md).

BIN
build/icons/1024x1024.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

BIN
build/icons/128x128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
build/icons/16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 553 B

BIN
build/icons/24x24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 963 B

BIN
build/icons/256x256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
build/icons/32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
build/icons/48x48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
build/icons/512x512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
build/icons/64x64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
build/icons/icon.icns Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 364 KiB

After

Width:  |  Height:  |  Size: 353 KiB

View File

@@ -1,5 +0,0 @@
{
"base": "tests/e2e",
"videos": "tests/e2e/videos",
"screenshots": "tests/e2e/videos"
}

View File

@@ -1,31 +1,18 @@
import { defineConfig } from 'cypress'; import { defineConfig } from 'cypress';
import ViteConfig from './vite.config'; import ViteConfig from './vite.config';
import cypressDirs from './cypress-dirs.json' assert { type: 'json' };
const CYPRESS_BASE_DIR = 'tests/e2e/';
export default defineConfig({ export default defineConfig({
fixturesFolder: `${cypressDirs.base}/fixtures`, fixturesFolder: `${CYPRESS_BASE_DIR}/fixtures`,
screenshotsFolder: cypressDirs.screenshots, screenshotsFolder: `${CYPRESS_BASE_DIR}/screenshots`,
video: true, video: true,
videosFolder: cypressDirs.videos, videosFolder: `${CYPRESS_BASE_DIR}/videos`,
e2e: { e2e: {
baseUrl: `http://localhost:${getApplicationPort()}/`, baseUrl: `http://localhost:${ViteConfig.server.port}/`,
specPattern: `${cypressDirs.base}/**/*.cy.{js,jsx,ts,tsx}`, // Default: cypress/e2e/**/*.cy.{js,jsx,ts,tsx} specPattern: `${CYPRESS_BASE_DIR}/**/*.cy.{js,jsx,ts,tsx}`, // Default: cypress/e2e/**/*.cy.{js,jsx,ts,tsx}
supportFile: `${cypressDirs.base}/support/e2e.ts`, supportFile: `${CYPRESS_BASE_DIR}/support/e2e.ts`,
}, },
/*
Disabling Chrome's web security to allow for faster DOM queries to access DOM earlier than
`cy.get()`. It bypasses the usual same-origin policy constraints
*/
chromeWebSecurity: false,
}); });
function getApplicationPort(): number {
const port = ViteConfig.server?.port;
if (port === undefined) {
throw new Error('Unknown application port');
}
return port;
}

View File

@@ -41,5 +41,5 @@ Application layer compiles templating syntax during parsing to create the end sc
The steps to extend the templating syntax: The steps to extend the templating syntax:
1. Add a new parser under [SyntaxParsers](./../src/application/Parser/Executable/Script/Compiler/Expressions/SyntaxParsers) where you can look at other parsers to understand more. 1. Add a new parser under [SyntaxParsers](./../src/application/Parser/Script/Compiler/Expressions/SyntaxParsers) where you can look at other parsers to understand more.
2. Register your in [CompositeExpressionParser](./../src/application/Parser/Executable/Script/Compiler/Expressions/Parser/CompositeExpressionParser.ts). 2. Register your in [CompositeExpressionParser](./../src/application/Parser/Script/Compiler/Expressions/Parser/CompositeExpressionParser.ts).

View File

@@ -27,14 +27,13 @@ Application uses highly decoupled models & services in different DDD layers:
**Domain layer**: **Domain layer**:
- Serves as the system's core and central truth. - Serves as the system's core and central truth.
- It should be independent of other layers and encapsulate the core business concepts. - Facilitates communication between the application and presentation layers through the domain model.
**Infrastructure layer**: **Infrastructure layer**:
- Provides technical implementations. - Manages technical implementations without dependencies on other layers or domain knowledge.
- Depends on the application and domain layers in terms of interfaces and contracts but should not include business logic.
![DDD + vue.js](./../img/architecture/app-ddd.drawio.png) ![DDD + vue.js](./../img/architecture/app-ddd.png)
### Application state ### Application state

View File

@@ -1,175 +1,192 @@
# Collection files # Collection files
privacy.sexy is a data-driven application that reads YAML files. - privacy.sexy is a data-driven application where it reads the necessary OS-specific logic from yaml files in [`application/collections`](./../src/application/collections/)
This document details the structure and syntax of the YAML files located in [`application/collections`](./../src/application/collections/), which form the backbone of the application's data model. The YAML schema [`.schema.yaml`](./../src/application/collections/.schema.yaml) is provided to provide better IDE support and be used in automated validations. - 💡 Best practices
- If you repeat yourself, try to utilize [YAML-defined functions](#function)
Related documentation: - Always try to add documentation and a way to revert a tweak in [scripts](#script)
- 📖 Types in code: [`collection.yaml.d.ts`](./../src/application/collections/collection.yaml.d.ts)
- 📖 [`Collections README`](./../src/application/collections/README.md) includes references to code as documentation.
- 📖 [Script Guidelines](./script-guidelines.md) provide guidance on script creation including best-practices.
## Objects ## Objects
### `Collection` ### `Collection`
- Defines categories, scripts, and OS-specific details in a tree structure. - A collection simply defines:
- Allows defining common [functions](#function) for code reuse. - different categories and their scripts in a tree structure
- OS specific details
- Also allows defining common [function](#function)s to be used throughout the collection if you'd like different scripts to share same code.
#### `Collection` syntax #### `Collection` syntax
- `os:` *`string`* **(required)** - `os:` *`string`* (**required**)
- Operating system for the collection. - Operating system that the [Collection](#collection) is written for.
- 📖 See [`OperatingSystem.ts`](./../src/domain/OperatingSystem.ts) for possible values. - 📖 See [OperatingSystem.ts](./../src/domain/OperatingSystem.ts) enumeration for allowed values.
- `actions: [` ***[`Category`](#category)*** `, ... ]` **(required)** - `actions: [` ***[`Category`](#category)*** `, ... ]` **(required)**
- Renders each parent category as cards in the user interface. - Each [category](#category) is rendered as different cards in card presentation.
- ❗ A [Collection](#collection) must consist of at least one category. - ❗ A [Collection](#collection) must consist of at least one category.
- `functions: [` ***[`Function`](#function)*** `, ... ]` - `functions: [` ***[`Function`](#function)*** `, ... ]`
- Optional for code reuse. - Functions are optionally defined to re-use the same code throughout different scripts.
- `scripting:` ***[`ScriptingDefinition`](#scriptingdefinition)*** **(required)** - `scripting:` ***[`ScriptingDefinition`](#scriptingdefinition)*** **(required)**
- Sets the scripting language for all inline code used within the collection. - Defines the scripting language that the code of other action uses.
### Executables ### `Category`
They represent independently executable actions with documentation and reversibility. - Category has a parent that has tree-like structure where it can have subcategories or subscripts.
- It's a logical grouping of different scripts and other categories.
An Executable is a logical entity that can #### `Category` syntax
- execute once compiled, - `category:` *`string`* (**required**)
- include a `docs` property for documentation. - Name of the category
- ❗ Must be unique throughout the [Collection](#collection)
It's either [Category](#category) or a [Script](#script). - `children: [` ***[`Category`](#category)*** `|` [***`Script`***](#script) `, ... ]` (**required**)
#### `Category`
Represents a logical group of scripts and subcategories.
##### `Category` syntax
- `category:` *`string`* **(required)**
- Name of the category.
- ❗ Must be unique throughout the [collection](#collection).
- `children: [` ***[`Category`](#category)*** `|` [***`Script`***](#script) `, ... ]` **(required)**
- ❗ Category must consist of at least one subcategory or script. - ❗ Category must consist of at least one subcategory or script.
- Children can be combination of scripts and subcategories. - Children can be combination of scripts and subcategories.
- `docs`: *`string`* | `[`*`string`*`, ... ]` - `docs`: *`string`* | `[`*`string`*`, ... ]`
- Markdown-formatted documentation related to the category. - Documentation pieces related to the category.
- Rendered as markdown.
#### `Script` ### `Script`
Represents an individual tweak. - Script represents a single tweak.
- A script can be of two different types (just like [functions](#function)):
1. Inline script; a script with an inline code
- Must define `code` property and optionally `revertCode` but not `call`
2. Caller script; a script that calls other functions
- Must define `call` property but not `code` or `revertCode`
- 🙏 For any new script, please add `revertCode` and `docs` values if possible.
Types (like [functions](#function)): #### `Script` syntax
1. Inline script: - `name`: *`string`* (**required**)
- Direct code. - Name of the script
-Requires `code` and optional `revertCode`. -Must be unique throughout the [Collection](#collection)
2. Caller script: - E.g. `Disable targeted ads`
- Calls other [functions](#function). - `code`: *`string`* (may be **required**)
- ❗ Requires `call`, but not `code` or `revertCode`. - Batch file commands that will be executed
- 💡 If defined, best practice to also define `revertCode`
📖 For detailed guidelines, see [Script Guidelines](./script-guidelines.md). - ❗ If not defined `call` must be defined, do not define if `call` is defined.
- `revertCode`: `string`
##### `Script` syntax - Code that'll undo the change done by `code` property.
- E.g. let's say `code` sets an environment variable as `setx POWERSHELL_TELEMETRY_OPTOUT 1`
- `name`: *`string`* **(required)** - then `revertCode` should be doing `setx POWERSHELL_TELEMETRY_OPTOUT 0`
- Script name. - ❗ Do not define if `call` is defined.
- ❗ Must be unique throughout the [Collection](#collection). - `call`: ***[`FunctionCall`](#functioncall)*** | `[` ***[`FunctionCall`](#functioncall)*** `, ... ]` (may be **required**)
- `code`: *`string`* **(conditionally required)** - A shared function or sequence of functions to call (called in order)
- Code to execute when the user selects the script. - ❗ If not defined `code` must be defined
- 💡 If defined, it's best practice to also define `revertCode`.
- ❗ Cannot co-exist with `call`, define either `code` with optional `revertCode` or `call`.
- `revertCode`: *`string`*
- Reverts changes made by `code`.
- ❗ Cannot co-exist with `call`, define `revertCode` with `code` or `call`.
- `call`: ***[`FunctionCall`](#functioncall)*** | `[` ***[`FunctionCall`](#functioncall)*** `, ... ]` **(conditionally required)**
- A shared function or sequence of functions to call (called in order).
- ❗ Cannot co-exist with `code` or `revertCode`, define `code` with optional `revertCode` or `call`.
- `docs`: *`string`* | `[`*`string`*`, ... ]` - `docs`: *`string`* | `[`*`string`*`, ... ]`
- Markdown-formatted documentation related to the script. - Documentation pieces related to the script.
- `recommend`: *`"standard"`* | *`"strict"`* | *`undefined`* (default: `undefined`) - Rendered as markdown.
- Sets recommendation level. - `recommend`: `"standard"` | `"strict"` | `undefined` (default)
- Application will not recommend the script if `undefined`. - If not defined then the script will not be recommended
- If defined it can be either
📖 For detailed guidelines, see [Script Guidelines](./script-guidelines.md). - `standard`: Only non-breaking scripts without limiting OS functionality
- `strict`: Scripts that can break certain functionality in favor of privacy and security
### `FunctionCall` ### `FunctionCall`
Specifies a function call. It may require providing argument values to its parameters. - Describes a single call to a function by optionally providing values to its parameters.
- 👀 See [parameter substitution](./templating.md#parameter-substitution) for an example usage
#### `FunctionCall` syntax #### `FunctionCall` syntax
- `function`: *`string`* **(required)** - `function`: *`string`* (**required**)
- Name of the function to call. - Name of the function to call.
- ❗ Function with same name must defined in `functions` property of [Collection](#collection). - ❗ Function with same name must defined in `functions` property of [Collection](#collection)
- `parameters`: `[` *`parameterName: parameterValue`* `, ... ]` - `parameters`: `[ parameterName:` *`parameterValue`*`, ... ]`
- Key-value pairs representing function parameters and their corresponding argument values. - Defines key value dictionary for each parameter and its value
- 📖 See [parameter substitution](./templating.md#parameter-substitution) for an example usage. - E.g.
- 💡 You can use [expressions (templating)](./templating.md#expressions) when providing argument values for parameters.
```yaml
parameters:
userDefinedParameterName: parameterValue
# ...
appName: Microsoft.WindowsFeedbackHub
```
- 💡 [Expressions (templating)](./templating.md#expressions) can be used as parameter value
### `Function` ### `Function`
- Enables reusable code in scripts. - Functions allow re-usable code throughout the defined scripts.
- Functions are templates compiled by privacy.sexy and uses special expression expressions. - Functions are templates compiled by privacy.sexy and uses special expression expressions.
- A function can be of two different types (like [scripts](#script)): - A function can be of two different types (just like [scripts](#script)):
1. Inline function: a function with an inline code. 1. Inline function: a function with an inline code.
- ❗ Requires `code` and optionally `revertCode`, but not `call`. - Must define `code` property and optionally `revertCode` but not `call`.
2. Caller function: a function that calls other functions. 2. Caller function: a function that calls other functions.
- ❗ Requires `call`, but not `code` or `revertCode`. - Must define `call` property but not `code` or `revertCode`.
- 📖 Read about function expressions in [Templating](./templating.md) with [example usages](./templating.md#parameter-substitution). - 👀 Read more on [Templating](./templating.md) for function expressions and [example usages](./templating.md#parameter-substitution).
#### `Function` syntax #### `Function` syntax
- `name`: *`string`* **(required)** - `name`: *`string`* (**required**)
- Name of the function that scripts will use. - Name of the function that scripts will use.
- ❗ Function names must be unique. - Convention is to use camelCase, and be verbs.
- ❗ Function names must follow camelCase and start with verbs (e.g., `uninstallStoreApp`). - E.g. `uninstallStoreApp`
- `parameters`: `[` ***[`FunctionParameter`](#functionparameter)*** `, ... ]` **(conditionally required)** - ❗ Function names must be unique
- Lists parameters used. - `parameters`: `[` ***[`FunctionParameter`](#functionparameter)*** `, ... ]`
- ❗ Required to be able use in [`FunctionCall`](#functioncall) or [expressions (templating)](./templating.md#expressions). - List of parameters that function code refers to.
- `code`: *`string`* **(conditionally required)** - ❗ Must be defined to be able use in [`FunctionCall`](#functioncall) or [expressions (templating)](./templating.md#expressions)
- Code to execute when the user selects the script. `code`: *`string`* (**required** if `call` is undefined)
- 💡 You can use [expressions (templating)](./templating.md#expressions) in its value. - Batch file commands that will be executed
- 💡 If defined, it's best practice to also define `revertCode`. - 💡 [Expressions (templating)](./templating.md#expressions) can be used in its value
- ❗ Cannot co-exist with `call`, define either `code` with optional `revertCode` or `call`. - 💡 If defined, best practice to also define `revertCode`
- ❗ If not defined `call` must be defined
- `revertCode`: *`string`* - `revertCode`: *`string`*
- Reverts changes made by `code`. - Code that'll undo the change done by `code` property.
- 💡 You can use [expressions (templating)](./templating.md#expressions) in its value. - E.g. let's say `code` sets an environment variable as `setx POWERSHELL_TELEMETRY_OPTOUT 1`
- ❗ Cannot co-exist with `call`, define `revertCode` with `code` or `call`. - then `revertCode` should be doing `setx POWERSHELL_TELEMETRY_OPTOUT 0`
- `call`: ***[`FunctionCall`](#functioncall)*** | `[` ***[`FunctionCall`](#functioncall)*** `, ... ]` **(conditionally required)** - 💡 [Expressions (templating)](./templating.md#expressions) can be used in code
- A shared function or sequence of functions to call (called in order). - `call`: ***[`FunctionCall`](#functioncall)*** | `[` ***[`FunctionCall`](#functioncall)*** `, ... ]` (may be **required**)
- 💡 You can use [expressions (templating)](./templating.md#expressions) in argument values provided for parameters. - A shared function or sequence of functions to call (called in order)
- ❗ Cannot co-exist with `code` or `revertCode`, define `code` with optional `revertCode` or `call`. - The parameter values that are sent can use [expressions (templating)](./templating.md#expressions)
- ❗ If not defined `code` must be defined
### `FunctionParameter` ### `FunctionParameter`
- Defines a single parameter that may require an argument value optionally or mandatory. - Defines a parameter that function requires optionally or mandatory.
- A [`FunctionCall`](#functioncall) provides argument values by a caller. - Its arguments are provided by a [Script](#script) through a [FunctionCall](#functioncall).
- A caller can be a [Script](#script) or [Function](#function).
#### `FunctionParameter` syntax #### `FunctionParameter` syntax
- `name`: *`string`* **(required)** - `name`: *`string`* (**required**)
- Name of the parameter that the function has. - Name of the parameters that the function has.
- ❗ Required for [expressions (templating)](./templating.md#expressions). - Parameter names must be defined to be used in [expressions (templating)](./templating.md#expressions).
-Must be unique and consists of alphanumeric characters. -Parameter names must be unique and include alphanumeric characters only.
- `optional`: *`boolean`* (default: `false`) - `optional`: *`boolean`* (default: `false`)
- Indicates the caller must provide and argument value for the parameter. - Specifies whether the caller [Script](#script) must provide any value for the parameter.
- 💡 If set to `false` i.e. an argument value is not optional then it expects a non-empty value for the variable. - If set to `false` i.e. an argument value is not optional then it expects a non-empty value for the variable;
- E.g., in a [`with` expression](./templating.md#with). - Otherwise it throws.
- 💡 Set it to `true` if you will use its argument value conditionally; - 💡 Set it to `true` if a parameter is used conditionally;
- Or else set it to `false` for verbosity or do not define it as default value is `false` anyway. - Or else set it to `false` for verbosity or do not define it as default value is `false` anyway.
- 💡 Can be used in conjunction with [`with` expression](./templating.md#with).
### `ScriptingDefinition` ### `ScriptingDefinition`
Sets global scripting properties for a [Collection](#collection). - Defines global properties for scripting that's used throughout its parent [Collection](#collection).
#### `ScriptingDefinition` syntax #### `ScriptingDefinition` syntax
- `language:` *`string`* **(required)** - `language:` *`string`* (**required**)
- 📖 See [`ScriptingLanguage.ts`](./../src/domain/ScriptingLanguage.ts) enumeration for allowed values. - 📖 See [ScriptingLanguage.ts](./../src/domain/ScriptingLanguage.ts) enumeration for allowed values.
- `startCode:` *`string`* **(required)** - `startCode:` *`string`* (**required**)
- Prepends the given code to the generated script file. - Code that'll be inserted on top of user created script.
- 💡 You can use global variables such as `$homepage`, `$version`, `$date` via [parameter substitution](./templating.md#parameter-substitution) code syntax such as `Welcome to {{ $homepage }}!`. - Global variables such as `$homepage`, `$version`, `$date` can be used using [parameter substitution](./templating.md#parameter-substitution) code syntax such as `Welcome to {{ $homepage }}!`
- `endCode:` *`string`* **(required)** - `endCode:` *`string`* (**required**)
- Appends to the given code to the generated script file. - Code that'll be inserted at the end of user created script.
- 💡 You can use global variables such as `$homepage`, `$version`, `$date` via [parameter substitution](./templating.md#parameter-substitution) code syntax such as `Welcome to {{ $homepage }}!`. - Global variables such as `$homepage`, `$version`, `$date` can be used using [parameter substitution](./templating.md#parameter-substitution) code syntax such as `Welcome to {{ $homepage }}!`
## Naming guidelines
- Prioritize consistency throughout all names.
- Use an instruction format like "do this, do that" for clear, direct guidance. This approach reduces potential confusion and offers easy-to-follow steps. It provides specific, unambiguous instructions.
- Ensure brand names adhere to their official casing.
- Choose clear and uncomplicated language.
- Favor the terms:
- "Disable" over "Turn off"
- "Configure" over "Set up"
- "Clear" over "Erase" or "Clean"
- "Minimize" over "Limit" or "Reduce" (when it enhances clarity)
- "Remove" over "Uninstall"
- Structure your phrases for clarity.
- For instance, "Disable XX telemetry" or "Clear XX data" are preferred over "Clear data from XX", "Disable telemetry in XX", or "Clear data of XX".
- Use sentence case rather than Title Case.

View File

@@ -1,95 +0,0 @@
# Desktop vs. Web Features
This table outlines the differences between the desktop and web versions of `privacy.sexy`.
| Feature | Desktop | Web |
| ------- | ------- | --- |
| [Usage without installation](#usage-without-installation) | 🔴 Not available | 🟢 Available |
| [Offline usage](#offline-usage) | 🟢 Available | 🟡 Partially available |
| [Auto-updates](#auto-updates) | 🟢 Available | 🟢 Available |
| [Logging](#logging) | 🟢 Available | 🔴 Not available |
| [Secure script execution/storage](#secure-script-executionstorage) | 🟢 Available | 🔴 Not available |
| [Native dialogs](#native-dialogs) | 🟢 Available | 🔴 Not available |
## Feature descriptions
### Usage without installation
You can use the web version directly in a browser without installation.
The desktop version requires download and installation.
> **Note for Linux users:** On Linux, privacy.sexy is available as an `AppImage`, a portable format that doesn't need traditional installation.
> This allows Linux users to use the desktop version without full installation, akin to the web version.
### Offline usage
The web version, once loaded, supports offline use.
Desktop version inherently allows offline usage.
### Auto-updates
Both the desktop and web versions of privacy.sexy provide timely access to the latest features and security improvements. The updates are automatically deployed from source code, reflecting the latest changes for enhanced security and reliability. For more details, see [CI/CD documentation](./../ci-cd.md).
The desktop version ensures secure delivery through cryptographic signatures and version checks.
[Security is a top priority](./../../SECURITY.md#update-security-and-integrity) at privacy.sexy.
> **Note for macOS users:**
> On macOS, the desktop version's auto-update process involves manual steps due to Apple's code signing costs.
> Users get notified about updates but might need to complete the installation manually.
> Updater stores update installation files temporarily at `$HOME/Library/Application Support/privacy.sexy/updates`.
> Consider [donating](https://github.com/sponsors/undergroundwires) to help improve this process ❤️.
### Logging
The desktop version supports logging of activities to aid in troubleshooting.
This feature is not available in the web version.
Log file locations vary by operating system:
- macOS: `$HOME/Library/Logs/privacy.sexy`
- Linux: `$HOME/.config/privacy.sexy/logs`
- Windows: `%APPDATA%\privacy.sexy\logs`
> 💡 privacy.sexy provides scripts to securely erase these logs.
### Secure script execution/storage
The desktop version of privacy.sexy enables direct script execution, providing a seamless and integrated experience.
This direct execution capability isn't available in the web version due to inherent browser restrictions.
**Script execution history:**
For enhanced auditability and easier troubleshooting, the desktop version keeps a record of executed scripts in designated directories.
These locations vary based on the operating system:
- macOS: `$HOME/Library/Application Support/privacy.sexy/runs`
- Linux: `$HOME/.config/privacy.sexy/runs`
- Windows: `%APPDATA%\privacy.sexy\runs`
> 💡 privacy.sexy provides scripts to securely erase your script execution history.
**Script antivirus scans:**
To enhance system protection, the desktop version of privacy.sexy automatically verifies the security of script
execution files by reading them back.
This process triggers antivirus scans to verify that scripts are safe before the execution.
**Script integrity checks:**
The desktop version of privacy.sexy implements robust integrity checks for both script execution and storage.
Featuring tamper protection, the application actively verifies the integrity of script files before executing or saving them.
If the actual contents of a script file do not align with the expected contents, the application refuses to execute or save the script.
This proactive approach ensures only unaltered and verified scripts undergo processing, thereby enhancing both security and reliability.
**Error handling:**
The desktop version of privacy.sexy features advanced error handling capabilities.
In scenarios where script execution or storage encounters failure, the desktop application initiates automated troubleshooting and self-healing processes.
It employs robust and reliable execution strategies, including self-healing mechanisms, and provides guidance and troubleshooting information to resolve issues effectively.
This proactive error handling and user guidance enhances the application's security and reliability.
### Native dialogs
The desktop version uses native dialogs, offering more features and reliability compared to the browser's file system dialogs.
These native dialogs provide a more integrated and user-friendly experience, aligning with the operating system's standard interface and functionalities.

View File

@@ -1,36 +0,0 @@
# System Requirements for the Desktop Version
The following system requirements are the official ones for the desktop version.
While we have tested and confirmed these requirements, the application might also work on other
systems or configurations that haven't undergone official testing.
## Windows
- **Version:** Windows 10 and later.
- **Processor:** Intel Pentium 4 or later.
- **Architecture:** 64-bit (x86-64), ARM (ARM64).
> **⚠️ Compatibility Note:**
> ARM version is only compatible with Windows 11 and later.
> It runs non-natively, leading to slower performance due to emulation [1].
## macOS
- **Version:** macOS Catalina (10.15) and later.
- **Architecture:** Intel-based (x86-64), Apple silicon (ARM64).
## Linux
- **Version:** Ubuntu 18.04 and later, Fedora 32 and later, and Debian 10 and later.
- **Processor:** Intel Pentium 4 or later.
- **Architecture:** 64-bit (x86-64).
## References
System requirements reflect Electron's platform capabilities [2] and Chromium's recommended configurations [3].
For details on the build process, see [electron-builder configuration file](./../../electron-builder.cjs).
[1]: https://web.archive.org/web/20240428082726/https://learn.microsoft.com/en-us/windows/arm/add-arm-support#emulation-on-arm-based-devices-for-x86-or-x64-windows-apps "Add support Arm devices to your Windows app | Microsoft Learn | learn.microsoft.com"
[2]: https://archive.ph/2024.04.28-082958/https://github.com/electron/electron/blob/main/README.md#platform-support "Platform Support | electron/README.md at main · electron/electron · GitHub | github.com"
[3]: https://web.archive.org/web/20240428082945/https://support.google.com/chrome/a/answer/7100626?hl=en "Chrome browser system requirements - Chrome Enterprise and Education Help | support.google.com"

View File

@@ -13,11 +13,8 @@ See [ci-cd.md](./ci-cd.md) for more information.
### Prerequisites ### Prerequisites
- Install Node.js: - Install Node >16.x.
- Refer to [action.yml](./../.github/actions/setup-node/action.yml) for the minimum required version compatible with the automated workflows.
- 💡 Recommended: Use [`nvm`](https://github.com/nvm-sh/nvm) CLI to install and switch between Node.js versions.
- Install dependencies using `npm install` (or [`npm run install-deps`](#utility-scripts) for more options). - Install dependencies using `npm install` (or [`npm run install-deps`](#utility-scripts) for more options).
- For Visual Studio Code users, running the configuration script is recommended to optimize the IDE settings, as detailed in [utility scripts](#utility-scripts).
### Testing ### Testing
@@ -39,7 +36,6 @@ See [ci-cd.md](./ci-cd.md) for more information.
- Markdown: `npm run lint:md` - Markdown: `npm run lint:md`
- Markdown consistency `npm run lint:md:consistency` - Markdown consistency `npm run lint:md:consistency`
- Markdown relative URLs: `npm run lint:md:relative-urls` - Markdown relative URLs: `npm run lint:md:relative-urls`
- Markdown external URLs: `npm run lint:md:external-urls`
- JavaScript/TypeScript: `npm run lint:eslint` - JavaScript/TypeScript: `npm run lint:eslint`
- Yaml: `npm run lint:yaml` - Yaml: `npm run lint:yaml`
@@ -81,10 +77,8 @@ See [ci-cd.md](./ci-cd.md) for more information.
- [**`npm run install-deps [-- <options>]`**](../scripts/npm-install.js): - [**`npm run install-deps [-- <options>]`**](../scripts/npm-install.js):
- Manages NPM dependency installation, it offers capabilities like doing a fresh install, retries on network errors, and other features. - Manages NPM dependency installation, it offers capabilities like doing a fresh install, retries on network errors, and other features.
- For example, you can run `npm run install-deps -- --fresh` to do clean installation of dependencies. - For example, you can run `npm run install-deps -- --fresh` to do clean installation of dependencies.
- [**`python3 ./scripts/configure_vscode.py`**](../scripts/configure_vscode.py): - [**`./scripts/configure-vscode.sh`**](../scripts/configure-vscode.sh):
- Optimizes Visual Studio Code settings and installs essential extensions, enhancing the development environment. - This script checks and sets the necessary configurations for VSCode in `settings.json` file.
- [**`python3 ./scripts/validate-collections-yaml`**](../scripts/validate-collections-yaml/README.md):
- Validates the syntax and structure of collection YAML files.
#### Automation scripts #### Automation scripts
@@ -100,4 +94,3 @@ See [ci-cd.md](./ci-cd.md) for more information.
You should use EditorConfig to follow project style. You should use EditorConfig to follow project style.
For Visual Studio Code, [`.vscode/extensions.json`](./../.vscode/extensions.json) includes list of recommended extensions. For Visual Studio Code, [`.vscode/extensions.json`](./../.vscode/extensions.json) includes list of recommended extensions.
You can use [VSCode configuration script](#utility-scripts) to automatically install those.

View File

@@ -11,41 +11,27 @@ The presentation layer uses an event-driven architecture for bidirectional react
## Structure ## Structure
- [`/src/` **`presentation/`**](./../src/presentation/): Contains Vue and Electron code. - [`/src/` **`presentation/`**](./../src/presentation/): Contains Vue and Electron code.
- [**`main.ts`**](./../src/presentation/main.ts): Starts Vue app.
- [**`index.html`**](./../src/presentation/index.html): The `index.html` entry file, located at the root of the project as required by Vite
- [**`bootstrapping/`**](./../src/presentation/bootstrapping/): Registers Vue components and plugins. - [**`bootstrapping/`**](./../src/presentation/bootstrapping/): Registers Vue components and plugins.
- [**`components/`**](./../src/presentation/components/): Contains Vue components, helpers and styles coupled to Vue components. - [**`components/`**](./../src/presentation/components/): Contains Vue components and helpers.
- [**`Shared/`**](./../src/presentation/components/Shared): Contains shared Vue components and helpers. - [**`Shared/`**](./../src/presentation/components/Shared): Contains shared Vue components and helpers.
- [**`Hooks`**](../src/presentation/components/Shared/Hooks): Hooks used by components through [dependency injection](#dependency-injections). - [**`Hooks`**](../src/presentation/components/Shared/Hooks): Hooks used by components through [dependency injection](#dependency-injections).
- [**`/public/`**](../src/presentation/public/): Contains static assets. - [**`/public/`**](../src/presentation/public/): Contains static assets.
- [**`assets/`**](./../src/presentation/assets/styles/): Contains assets processed by Vite. - [**`assets/`**](./../src/presentation/assets/styles/): Contains assets processed by Vite.
- [**`fonts/`**](./../src/presentation/assets/fonts/): Contains fonts. - [**`fonts/`**](./../src/presentation/assets/fonts/): Contains fonts.
- [**`styles/`**](./../src/presentation/assets/styles/): Contains shared styles. - [**`styles/`**](./../src/presentation/assets/styles/): Contains shared styles.
- [**`main.scss`**](./../src/presentation/assets/styles/main.scss): Main Sass file, imported by other components as single entrypoint.. - [**`components/`**](./../src/presentation/assets/styles/components): Contains styles coupled to Vue components.
- [**`main.scss`**](./../src/presentation/assets/styles/main.scss): Main Sass file, imported by other components as single entrypoint.
- [**`main.ts`**](./../src/presentation/main.ts): Starts Vue app.
- [**`electron/`**](./../src/presentation/electron/): Contains Electron code. - [**`electron/`**](./../src/presentation/electron/): Contains Electron code.
- [`/main/` **`index.ts`**](./../src/presentation/electron/main/index.ts): Main entry for Electron, managing application windows and lifecycle events. - [`/main/` **`index.ts`**](./../src/presentation/main.ts): Main entry for Electron, managing application windows and lifecycle events.
- [`/preload/` **`index.ts`**](./../src/presentation/electron/preload/index.ts): Script executed before the renderer, securing Node.js features for renderer use. - [`/preload/` **`index.ts`**](./../src/presentation/main.ts): Script executed before the renderer, securing Node.js features for renderer use.
- [**`/shared/`**](./../src/presentation/electron/shared/): Shared logic between different Electron processes.
- [**`/build/`**](./../src/presentation/electron/build/): `electron-builder` build resources directory, [README.md](./../src/presentation/electron/build/README.md).
- [**`/vite.config.ts`**](./../vite.config.ts): Contains Vite configurations for building web application. - [**`/vite.config.ts`**](./../vite.config.ts): Contains Vite configurations for building web application.
- [**`/electron.vite.config.ts`**](./../electron.vite.config.ts): Contains Vite configurations for building desktop applications. - [**`/electron.vite.config.ts`**](./../electron.vite.config.ts): Contains Vite configurations for building desktop applications.
- [**`/postcss.config.cjs`**](./../postcss.config.cjs): Contains PostCSS configurations for Vite. - [**`/postcss.config.cjs`**](./../postcss.config.cjs): Contains PostCSS configurations for Vite.
## Visual design best-practices ## Visual design best-practices
- **Clickables**: Add visual clues for clickable items. It should be as clear as possible that they're interactable at first look without hovering. They should also have different visual state when hovering/touching on them that indicates that they are being clicked, which helps with accessibility.
Add visual clues for clickable items.
It should be as clear as possible that they're interactable at first look without hovering.
They should also have different visual state when hovering/touching on them that indicates that they are being clicked, which helps with accessibility.
- **Borders**:
privacy.sexy prefers sharper edges in its design language.
- **Fonts**:
- Use the primary font for regular text and monospace font for code or specific data.
- Use cursive and logo fonts solely for branding.
- Refer to [standardized font size variables](../src/presentation/assets/styles/_typography.scss) for font sizing, avoiding arbitrary `px`, `em`, `rem`, or percentage values.
- **Spacing**:
Use [global spacing variables](../src/presentation/assets/styles/_spacing.scss) for consistent margin, padding, and gap definitions.
This provides uniform spatial distribution and alignment of elements, enhancing visual harmony and making the UI more scalable and maintainable.
## Application data ## Application data
@@ -84,30 +70,26 @@ To add a new dependency:
1. **Define its symbol**: Define an associated symbol for every dependency in [`injectionSymbols.ts`](./../src/presentation/injectionSymbols.ts). Symbols are grouped into: 1. **Define its symbol**: Define an associated symbol for every dependency in [`injectionSymbols.ts`](./../src/presentation/injectionSymbols.ts). Symbols are grouped into:
- **Singletons**: Shared across components, instantiated once. - **Singletons**: Shared across components, instantiated once.
- **Transients**: Factories yielding a new instance on every access. - **Transients**: Factories yielding a new instance on every access.
2. **Provide the dependency**: 2. **Provide the dependency**: Modify the [`provideDependencies`](./../src/presentation/bootstrapping/DependencyProvider.ts) function to include the new dependency. [`App.vue`](./../src/presentation/components/App.vue) calls this function within its `setup()` hook to register the dependencies.
Modify the [`provideDependencies`](./../src/presentation/bootstrapping/DependencyProvider.ts) function to include the new dependency. 3. **Inject the dependency**: Use Vue's `inject` method alongside the defined symbol to incorporate the dependency into components.
[`App.vue`](./../src/presentation/components/App.vue) calls this function within its `setup()` hook to register the dependencies. - For singletons, invoke the factory method: `inject(symbolKey)()`.
3. **Inject the dependency**: Use `injectKey` to inject a dependency. Pass a selector function to `injectKey` that retrieves the appropriate symbol from the provided dependencies. - For transients, directly inject: `inject(symbolKey)`.
- Example usage: `injectKey((keys) => keys.useCollectionState)`;
## Shared UI components ## Shared UI components
Shared UI components ensure consistency and streamline front-end development. Shared UI components promote consistency and simplifies the creation of the front-end.
We use homegrown components over third-party solutions or comprehensive UI frameworks like Quasar to maintain portability and easy maintenance. In order to maintain portability and easy maintainability, the preference is towards using homegrown components over third-party ones or comprehensive UI frameworks like Quasar.
Shared components include: Shared components include:
- [ModalDialog.vue](./../src/presentation/components/Shared/Modal/ModalDialog.vue): Renders modal windows. - [ModalDialog.vue](./../src/presentation/components/Shared/Modal/ModalDialog.vue) is utilized for rendering modal windows.
- [TooltipWrapper.vue](./../src/presentation/components/Shared/TooltipWrapper.vue): Provides tooltip functionality for improved information accessibility. - [TooltipWrapper.vue](./../src/presentation/components/Shared/TooltipWrapper.vue) acts as a wrapper for rendering tooltips.
- [FlatButton.vue](./../src/presentation/components/Shared/FlatButton.vue): Creates flat-style buttons for a unified and consistent user interface.
## Desktop builds ## Desktop builds
Desktop builds uses `electron-vite` to bundle the code, and `electron-builder` to build and publish the packages. Desktop builds uses `electron-vite` to bundle the code, and `electron-builder` to build and publish the packages.
Host system access is strictly controlled. The [`preloader`](./../src/presentation/electron/preload/) isolates logic that interacts with the host system. These functionalities are then securely exposed to the renderer process (Vue application) using context-bridging. [`ApiContextBridge.ts`](./../src/presentation/electron/preload/ContextBridging/ApiContextBridge.ts) handles the configuration of the exposed APIs, ensuring a secure bridge between the Electron and Vue layers.
## Styles ## Styles
### Style location ### Style location

View File

@@ -1,24 +0,0 @@
# Research Documentation
Welcome to the research section of privacy.sexy.
This area houses in-depth technical research and analyses, serving as a resource for developers, contributors, and technology enthusiasts.
**Structure:**
This folder organizes research into topic-specific subdirectories like `windows`, `linux`, etc.
Each contains materials relevant to its subject.
**Contents:**
These documents offer comprehensive insights into the respective topics, supporting development and contributions.
**Contributing:**
Contributions to our research documentation are welcome.
If your research aligns with privacy.sexy goals, please consider adding it here.
See [`CONTRIBUTING.md`](./../../CONTRIBUTING.md) on more information about how to contribute.
**Usage:**
This information is available for educational and research purposes.
We support knowledge sharing and aim to enhance understanding of privacy and security technologies.

View File

@@ -1,84 +0,0 @@
Name PublisherId Category NonRemovable
---- ----------- -------- ------------
1527c705-839a-4832-9118-54d4Bd6a0c89 cw5n1h2txyewy System True
c5e2524a-ea46-4f67-841f-6a9465d9d515 cw5n1h2txyewy System True
E2A4F912-2574-4A75-9BB0-0D023378592B cw5n1h2txyewy System True
F46D4000-FD22-4DB4-AC8E-4E1DDDE828FE cw5n1h2txyewy System True
InputApp cw5n1h2txyewy System True
Microsoft.AAD.BrokerPlugin cw5n1h2txyewy System True
Microsoft.AccountsControl cw5n1h2txyewy System True
Microsoft.AsyncTextService 8wekyb3d8bbwe System True
Microsoft.BingWeather 8wekyb3d8bbwe Provisioned False
Microsoft.BioEnrollment cw5n1h2txyewy System True
Microsoft.CredDialogHost cw5n1h2txyewy System True
Microsoft.DesktopAppInstaller 8wekyb3d8bbwe Provisioned False
Microsoft.ECApp 8wekyb3d8bbwe System True
Microsoft.GetHelp 8wekyb3d8bbwe Provisioned False
Microsoft.Getstarted 8wekyb3d8bbwe Provisioned False
Microsoft.HEIFImageExtension 8wekyb3d8bbwe Provisioned False
Microsoft.LockApp cw5n1h2txyewy System True
Microsoft.Messaging 8wekyb3d8bbwe Provisioned False
Microsoft.Microsoft3DViewer 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftEdge 8wekyb3d8bbwe System True
Microsoft.MicrosoftEdgeDevToolsClient 8wekyb3d8bbwe System True
Microsoft.MicrosoftOfficeHub 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftSolitaireCollection 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftStickyNotes 8wekyb3d8bbwe Provisioned False
Microsoft.MixedReality.Portal 8wekyb3d8bbwe Provisioned False
Microsoft.MSPaint 8wekyb3d8bbwe Provisioned False
Microsoft.Office.OneNote 8wekyb3d8bbwe Provisioned False
Microsoft.OneConnect 8wekyb3d8bbwe Provisioned False
Microsoft.People 8wekyb3d8bbwe Provisioned False
Microsoft.PPIProjection cw5n1h2txyewy System True
Microsoft.Print3D 8wekyb3d8bbwe Provisioned False
Microsoft.ScreenSketch 8wekyb3d8bbwe Provisioned False
Microsoft.SkypeApp kzf8qxf38zg5c Provisioned False
Microsoft.StorePurchaseApp 8wekyb3d8bbwe Provisioned False
Microsoft.VP9VideoExtensions 8wekyb3d8bbwe Provisioned False
Microsoft.Wallet 8wekyb3d8bbwe Provisioned False
Microsoft.WebMediaExtensions 8wekyb3d8bbwe Provisioned False
Microsoft.WebpImageExtension 8wekyb3d8bbwe Provisioned False
Microsoft.Win32WebViewHost cw5n1h2txyewy System True
Microsoft.Windows.Apprep.ChxApp cw5n1h2txyewy System True
Microsoft.Windows.AssignedAccessLockApp cw5n1h2txyewy System True
Microsoft.Windows.CallingShellApp cw5n1h2txyewy System True
Microsoft.Windows.CapturePicker cw5n1h2txyewy System True
Microsoft.Windows.CloudExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.ContentDeliveryManager cw5n1h2txyewy System True
Microsoft.Windows.Cortana cw5n1h2txyewy System True
Microsoft.Windows.NarratorQuickStart 8wekyb3d8bbwe System True
Microsoft.Windows.OOBENetworkCaptivePortal cw5n1h2txyewy System True
Microsoft.Windows.OOBENetworkConnectionFlow cw5n1h2txyewy System True
Microsoft.Windows.ParentalControls cw5n1h2txyewy System True
Microsoft.Windows.PeopleExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.Photos 8wekyb3d8bbwe Provisioned False
Microsoft.Windows.PinningConfirmationDialog cw5n1h2txyewy System True
Microsoft.Windows.SecHealthUI cw5n1h2txyewy System True
Microsoft.Windows.SecureAssessmentBrowser cw5n1h2txyewy System True
Microsoft.Windows.ShellExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.StartMenuExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.XGpuEjectDialog cw5n1h2txyewy System True
Microsoft.WindowsAlarms 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsCalculator 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsCamera 8wekyb3d8bbwe Provisioned False
microsoft.windowscommunicationsapps 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsFeedbackHub 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsMaps 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsSoundRecorder 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsStore 8wekyb3d8bbwe Provisioned False
Microsoft.Xbox.TCUI 8wekyb3d8bbwe Provisioned False
Microsoft.XboxApp 8wekyb3d8bbwe Provisioned False
Microsoft.XboxGameCallableUI cw5n1h2txyewy System True
Microsoft.XboxGameOverlay 8wekyb3d8bbwe Provisioned False
Microsoft.XboxGamingOverlay 8wekyb3d8bbwe Provisioned False
Microsoft.XboxIdentityProvider 8wekyb3d8bbwe Provisioned False
Microsoft.XboxSpeechToTextOverlay 8wekyb3d8bbwe Provisioned False
Microsoft.YourPhone 8wekyb3d8bbwe Provisioned False
Microsoft.ZuneMusic 8wekyb3d8bbwe Provisioned False
Microsoft.ZuneVideo 8wekyb3d8bbwe Provisioned False
Windows.CBSPreview cw5n1h2txyewy System True
windows.immersivecontrolpanel cw5n1h2txyewy System True
Windows.PrintDialog cw5n1h2txyewy System True

View File

@@ -1,85 +0,0 @@
Name PublisherId Category NonRemovable
---- ----------- -------- ------------
1527c705-839a-4832-9118-54d4Bd6a0c89 cw5n1h2txyewy System True
c5e2524a-ea46-4f67-841f-6a9465d9d515 cw5n1h2txyewy System True
E2A4F912-2574-4A75-9BB0-0D023378592B cw5n1h2txyewy System True
F46D4000-FD22-4DB4-AC8E-4E1DDDE828FE cw5n1h2txyewy System True
Microsoft.549981C3F5F10 8wekyb3d8bbwe Provisioned False
Microsoft.AAD.BrokerPlugin cw5n1h2txyewy System True
Microsoft.AccountsControl cw5n1h2txyewy System True
Microsoft.AsyncTextService 8wekyb3d8bbwe System True
Microsoft.BingWeather 8wekyb3d8bbwe Provisioned False
Microsoft.BioEnrollment cw5n1h2txyewy System True
Microsoft.CredDialogHost cw5n1h2txyewy System True
Microsoft.DesktopAppInstaller 8wekyb3d8bbwe Provisioned False
Microsoft.ECApp 8wekyb3d8bbwe System True
Microsoft.GetHelp 8wekyb3d8bbwe Provisioned False
Microsoft.Getstarted 8wekyb3d8bbwe Provisioned False
Microsoft.HEIFImageExtension 8wekyb3d8bbwe Provisioned False
Microsoft.LockApp cw5n1h2txyewy System True
Microsoft.Microsoft3DViewer 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftEdge 8wekyb3d8bbwe System True
Microsoft.MicrosoftEdge.Stable 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftEdgeDevToolsClient 8wekyb3d8bbwe System True
Microsoft.MicrosoftOfficeHub 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftSolitaireCollection 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftStickyNotes 8wekyb3d8bbwe Provisioned False
Microsoft.MixedReality.Portal 8wekyb3d8bbwe Provisioned False
Microsoft.MSPaint 8wekyb3d8bbwe Provisioned False
Microsoft.Office.OneNote 8wekyb3d8bbwe Provisioned False
Microsoft.People 8wekyb3d8bbwe Provisioned False
Microsoft.ScreenSketch 8wekyb3d8bbwe Provisioned False
Microsoft.SkypeApp kzf8qxf38zg5c Provisioned False
Microsoft.StorePurchaseApp 8wekyb3d8bbwe Provisioned False
Microsoft.VCLibs.140.00 8wekyb3d8bbwe Provisioned False
Microsoft.VP9VideoExtensions 8wekyb3d8bbwe Provisioned False
Microsoft.Wallet 8wekyb3d8bbwe Provisioned False
Microsoft.WebMediaExtensions 8wekyb3d8bbwe Provisioned False
Microsoft.WebpImageExtension 8wekyb3d8bbwe Provisioned False
Microsoft.Win32WebViewHost cw5n1h2txyewy System True
Microsoft.Windows.Apprep.ChxApp cw5n1h2txyewy System True
Microsoft.Windows.AssignedAccessLockApp cw5n1h2txyewy System True
Microsoft.Windows.CallingShellApp cw5n1h2txyewy System True
Microsoft.Windows.CapturePicker cw5n1h2txyewy System True
Microsoft.Windows.CloudExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.ContentDeliveryManager cw5n1h2txyewy System True
Microsoft.Windows.NarratorQuickStart 8wekyb3d8bbwe System True
Microsoft.Windows.OOBENetworkCaptivePortal cw5n1h2txyewy System True
Microsoft.Windows.OOBENetworkConnectionFlow cw5n1h2txyewy System True
Microsoft.Windows.ParentalControls cw5n1h2txyewy System True
Microsoft.Windows.PeopleExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.Photos 8wekyb3d8bbwe Provisioned False
Microsoft.Windows.PinningConfirmationDialog cw5n1h2txyewy System True
Microsoft.Windows.Search cw5n1h2txyewy System True
Microsoft.Windows.SecHealthUI cw5n1h2txyewy System True
Microsoft.Windows.SecureAssessmentBrowser cw5n1h2txyewy System True
Microsoft.Windows.ShellExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.StartMenuExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.XGpuEjectDialog cw5n1h2txyewy System True
Microsoft.WindowsAlarms 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsCalculator 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsCamera 8wekyb3d8bbwe Provisioned False
microsoft.windowscommunicationsapps 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsFeedbackHub 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsMaps 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsSoundRecorder 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsStore 8wekyb3d8bbwe Provisioned False
Microsoft.Xbox.TCUI 8wekyb3d8bbwe Provisioned False
Microsoft.XboxApp 8wekyb3d8bbwe Provisioned False
Microsoft.XboxGameCallableUI cw5n1h2txyewy System True
Microsoft.XboxGameOverlay 8wekyb3d8bbwe Provisioned False
Microsoft.XboxGamingOverlay 8wekyb3d8bbwe Provisioned False
Microsoft.XboxIdentityProvider 8wekyb3d8bbwe Provisioned False
Microsoft.XboxSpeechToTextOverlay 8wekyb3d8bbwe Provisioned False
Microsoft.YourPhone 8wekyb3d8bbwe Provisioned False
Microsoft.ZuneMusic 8wekyb3d8bbwe Provisioned False
Microsoft.ZuneVideo 8wekyb3d8bbwe Provisioned False
MicrosoftWindows.Client.CBS cw5n1h2txyewy System True
MicrosoftWindows.UndockedDevKit cw5n1h2txyewy System True
NcsiUwpApp 8wekyb3d8bbwe System True
Windows.CBSPreview cw5n1h2txyewy System True
windows.immersivecontrolpanel cw5n1h2txyewy System True
Windows.PrintDialog cw5n1h2txyewy System True

View File

@@ -1,85 +0,0 @@
Name PublisherId Category NonRemovable
---- ----------- -------- ------------
1527c705-839a-4832-9118-54d4Bd6a0c89 cw5n1h2txyewy System True
c5e2524a-ea46-4f67-841f-6a9465d9d515 cw5n1h2txyewy System True
E2A4F912-2574-4A75-9BB0-0D023378592B cw5n1h2txyewy System True
F46D4000-FD22-4DB4-AC8E-4E1DDDE828FE cw5n1h2txyewy System True
Microsoft.549981C3F5F10 8wekyb3d8bbwe Provisioned False
Microsoft.AAD.BrokerPlugin cw5n1h2txyewy System True
Microsoft.AccountsControl cw5n1h2txyewy System True
Microsoft.AsyncTextService 8wekyb3d8bbwe System True
Microsoft.BingWeather 8wekyb3d8bbwe Provisioned False
Microsoft.BioEnrollment cw5n1h2txyewy System True
Microsoft.CredDialogHost cw5n1h2txyewy System True
Microsoft.DesktopAppInstaller 8wekyb3d8bbwe Provisioned False
Microsoft.ECApp 8wekyb3d8bbwe System True
Microsoft.GetHelp 8wekyb3d8bbwe Provisioned False
Microsoft.Getstarted 8wekyb3d8bbwe Provisioned False
Microsoft.HEIFImageExtension 8wekyb3d8bbwe Provisioned False
Microsoft.LockApp cw5n1h2txyewy System True
Microsoft.Microsoft3DViewer 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftEdge 8wekyb3d8bbwe System True
Microsoft.MicrosoftEdge.Stable 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftEdgeDevToolsClient 8wekyb3d8bbwe System True
Microsoft.MicrosoftOfficeHub 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftSolitaireCollection 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftStickyNotes 8wekyb3d8bbwe Provisioned False
Microsoft.MixedReality.Portal 8wekyb3d8bbwe Provisioned False
Microsoft.MSPaint 8wekyb3d8bbwe Provisioned False
Microsoft.Office.OneNote 8wekyb3d8bbwe Provisioned False
Microsoft.People 8wekyb3d8bbwe Provisioned False
Microsoft.ScreenSketch 8wekyb3d8bbwe Provisioned False
Microsoft.SkypeApp kzf8qxf38zg5c Provisioned False
Microsoft.StorePurchaseApp 8wekyb3d8bbwe Provisioned False
Microsoft.VCLibs.140.00 8wekyb3d8bbwe Provisioned False
Microsoft.VP9VideoExtensions 8wekyb3d8bbwe Provisioned False
Microsoft.Wallet 8wekyb3d8bbwe Provisioned False
Microsoft.WebMediaExtensions 8wekyb3d8bbwe Provisioned False
Microsoft.WebpImageExtension 8wekyb3d8bbwe Provisioned False
Microsoft.Win32WebViewHost cw5n1h2txyewy System True
Microsoft.Windows.Apprep.ChxApp cw5n1h2txyewy System True
Microsoft.Windows.AssignedAccessLockApp cw5n1h2txyewy System True
Microsoft.Windows.CallingShellApp cw5n1h2txyewy System True
Microsoft.Windows.CapturePicker cw5n1h2txyewy System True
Microsoft.Windows.CloudExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.ContentDeliveryManager cw5n1h2txyewy System True
Microsoft.Windows.NarratorQuickStart 8wekyb3d8bbwe System True
Microsoft.Windows.OOBENetworkCaptivePortal cw5n1h2txyewy System True
Microsoft.Windows.OOBENetworkConnectionFlow cw5n1h2txyewy System True
Microsoft.Windows.ParentalControls cw5n1h2txyewy System True
Microsoft.Windows.PeopleExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.Photos 8wekyb3d8bbwe Provisioned False
Microsoft.Windows.PinningConfirmationDialog cw5n1h2txyewy System True
Microsoft.Windows.Search cw5n1h2txyewy System True
Microsoft.Windows.SecHealthUI cw5n1h2txyewy System True
Microsoft.Windows.SecureAssessmentBrowser cw5n1h2txyewy System True
Microsoft.Windows.ShellExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.StartMenuExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.XGpuEjectDialog cw5n1h2txyewy System True
Microsoft.WindowsAlarms 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsCalculator 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsCamera 8wekyb3d8bbwe Provisioned False
microsoft.windowscommunicationsapps 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsFeedbackHub 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsMaps 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsSoundRecorder 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsStore 8wekyb3d8bbwe Provisioned False
Microsoft.Xbox.TCUI 8wekyb3d8bbwe Provisioned False
Microsoft.XboxApp 8wekyb3d8bbwe Provisioned False
Microsoft.XboxGameCallableUI cw5n1h2txyewy System True
Microsoft.XboxGameOverlay 8wekyb3d8bbwe Provisioned False
Microsoft.XboxGamingOverlay 8wekyb3d8bbwe Provisioned False
Microsoft.XboxIdentityProvider 8wekyb3d8bbwe Provisioned False
Microsoft.XboxSpeechToTextOverlay 8wekyb3d8bbwe Provisioned False
Microsoft.YourPhone 8wekyb3d8bbwe Provisioned False
Microsoft.ZuneMusic 8wekyb3d8bbwe Provisioned False
Microsoft.ZuneVideo 8wekyb3d8bbwe Provisioned False
MicrosoftWindows.Client.CBS cw5n1h2txyewy System True
MicrosoftWindows.UndockedDevKit cw5n1h2txyewy System True
NcsiUwpApp 8wekyb3d8bbwe System True
Windows.CBSPreview cw5n1h2txyewy System True
windows.immersivecontrolpanel cw5n1h2txyewy System True
Windows.PrintDialog cw5n1h2txyewy System True

View File

@@ -1,85 +0,0 @@
Name PublisherId Category NonRemovable
---- ----------- -------- ------------
1527c705-839a-4832-9118-54d4Bd6a0c89 cw5n1h2txyewy System True
c5e2524a-ea46-4f67-841f-6a9465d9d515 cw5n1h2txyewy System True
E2A4F912-2574-4A75-9BB0-0D023378592B cw5n1h2txyewy System True
F46D4000-FD22-4DB4-AC8E-4E1DDDE828FE cw5n1h2txyewy System True
Microsoft.549981C3F5F10 8wekyb3d8bbwe Provisioned False
Microsoft.AAD.BrokerPlugin cw5n1h2txyewy System True
Microsoft.AccountsControl cw5n1h2txyewy System True
Microsoft.AsyncTextService 8wekyb3d8bbwe System True
Microsoft.BingWeather 8wekyb3d8bbwe Provisioned False
Microsoft.BioEnrollment cw5n1h2txyewy System True
Microsoft.CredDialogHost cw5n1h2txyewy System True
Microsoft.DesktopAppInstaller 8wekyb3d8bbwe Provisioned False
Microsoft.ECApp 8wekyb3d8bbwe System True
Microsoft.GetHelp 8wekyb3d8bbwe Provisioned False
Microsoft.Getstarted 8wekyb3d8bbwe Provisioned False
Microsoft.HEIFImageExtension 8wekyb3d8bbwe Provisioned False
Microsoft.LockApp cw5n1h2txyewy System True
Microsoft.Microsoft3DViewer 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftEdge 8wekyb3d8bbwe System True
Microsoft.MicrosoftEdge.Stable 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftEdgeDevToolsClient 8wekyb3d8bbwe System True
Microsoft.MicrosoftOfficeHub 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftSolitaireCollection 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftStickyNotes 8wekyb3d8bbwe Provisioned False
Microsoft.MixedReality.Portal 8wekyb3d8bbwe Provisioned False
Microsoft.MSPaint 8wekyb3d8bbwe Provisioned False
Microsoft.Office.OneNote 8wekyb3d8bbwe Provisioned False
Microsoft.People 8wekyb3d8bbwe Provisioned False
Microsoft.ScreenSketch 8wekyb3d8bbwe Provisioned False
Microsoft.SkypeApp kzf8qxf38zg5c Provisioned False
Microsoft.StorePurchaseApp 8wekyb3d8bbwe Provisioned False
Microsoft.VCLibs.140.00 8wekyb3d8bbwe Provisioned False
Microsoft.VP9VideoExtensions 8wekyb3d8bbwe Provisioned False
Microsoft.Wallet 8wekyb3d8bbwe Provisioned False
Microsoft.WebMediaExtensions 8wekyb3d8bbwe Provisioned False
Microsoft.WebpImageExtension 8wekyb3d8bbwe Provisioned False
Microsoft.Win32WebViewHost cw5n1h2txyewy System True
Microsoft.Windows.Apprep.ChxApp cw5n1h2txyewy System True
Microsoft.Windows.AssignedAccessLockApp cw5n1h2txyewy System True
Microsoft.Windows.CallingShellApp cw5n1h2txyewy System True
Microsoft.Windows.CapturePicker cw5n1h2txyewy System True
Microsoft.Windows.CloudExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.ContentDeliveryManager cw5n1h2txyewy System True
Microsoft.Windows.NarratorQuickStart 8wekyb3d8bbwe System True
Microsoft.Windows.OOBENetworkCaptivePortal cw5n1h2txyewy System True
Microsoft.Windows.OOBENetworkConnectionFlow cw5n1h2txyewy System True
Microsoft.Windows.ParentalControls cw5n1h2txyewy System True
Microsoft.Windows.PeopleExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.Photos 8wekyb3d8bbwe Provisioned False
Microsoft.Windows.PinningConfirmationDialog cw5n1h2txyewy System True
Microsoft.Windows.Search cw5n1h2txyewy System True
Microsoft.Windows.SecHealthUI cw5n1h2txyewy System True
Microsoft.Windows.SecureAssessmentBrowser cw5n1h2txyewy System True
Microsoft.Windows.ShellExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.StartMenuExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.XGpuEjectDialog cw5n1h2txyewy System True
Microsoft.WindowsAlarms 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsCalculator 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsCamera 8wekyb3d8bbwe Provisioned False
microsoft.windowscommunicationsapps 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsFeedbackHub 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsMaps 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsSoundRecorder 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsStore 8wekyb3d8bbwe Provisioned False
Microsoft.Xbox.TCUI 8wekyb3d8bbwe Provisioned False
Microsoft.XboxApp 8wekyb3d8bbwe Provisioned False
Microsoft.XboxGameCallableUI cw5n1h2txyewy System True
Microsoft.XboxGameOverlay 8wekyb3d8bbwe Provisioned False
Microsoft.XboxGamingOverlay 8wekyb3d8bbwe Provisioned False
Microsoft.XboxIdentityProvider 8wekyb3d8bbwe Provisioned False
Microsoft.XboxSpeechToTextOverlay 8wekyb3d8bbwe Provisioned False
Microsoft.YourPhone 8wekyb3d8bbwe Provisioned False
Microsoft.ZuneMusic 8wekyb3d8bbwe Provisioned False
Microsoft.ZuneVideo 8wekyb3d8bbwe Provisioned False
MicrosoftWindows.Client.CBS cw5n1h2txyewy System True
MicrosoftWindows.UndockedDevKit cw5n1h2txyewy System True
NcsiUwpApp 8wekyb3d8bbwe System True
Windows.CBSPreview cw5n1h2txyewy System True
windows.immersivecontrolpanel cw5n1h2txyewy System True
Windows.PrintDialog cw5n1h2txyewy System True

View File

@@ -1,88 +0,0 @@
Name PublisherId Category NonRemovable
---- ----------- -------- ------------
1527c705-839a-4832-9118-54d4Bd6a0c89 cw5n1h2txyewy System True
c5e2524a-ea46-4f67-841f-6a9465d9d515 cw5n1h2txyewy System True
E2A4F912-2574-4A75-9BB0-0D023378592B cw5n1h2txyewy System True
F46D4000-FD22-4DB4-AC8E-4E1DDDE828FE cw5n1h2txyewy System True
Microsoft.549981C3F5F10 8wekyb3d8bbwe Provisioned False
Microsoft.AAD.BrokerPlugin cw5n1h2txyewy System True
Microsoft.AccountsControl cw5n1h2txyewy System True
Microsoft.AsyncTextService 8wekyb3d8bbwe System True
Microsoft.BingNews 8wekyb3d8bbwe Provisioned False
Microsoft.BingWeather 8wekyb3d8bbwe Provisioned False
Microsoft.BioEnrollment cw5n1h2txyewy System True
Microsoft.CredDialogHost cw5n1h2txyewy System True
Microsoft.DesktopAppInstaller 8wekyb3d8bbwe Provisioned True
Microsoft.ECApp 8wekyb3d8bbwe System True
Microsoft.GamingApp 8wekyb3d8bbwe Provisioned False
Microsoft.GetHelp 8wekyb3d8bbwe Provisioned False
Microsoft.Getstarted 8wekyb3d8bbwe Provisioned False
Microsoft.HEIFImageExtension 8wekyb3d8bbwe Provisioned False
Microsoft.LockApp cw5n1h2txyewy System True
Microsoft.MicrosoftEdge 8wekyb3d8bbwe System True
Microsoft.MicrosoftEdge.Stable 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftEdgeDevToolsClient 8wekyb3d8bbwe System True
Microsoft.MicrosoftOfficeHub 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftSolitaireCollection 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftStickyNotes 8wekyb3d8bbwe Provisioned False
Microsoft.OneDriveSync 8wekyb3d8bbwe Installed False
Microsoft.Paint 8wekyb3d8bbwe Provisioned False
Microsoft.People 8wekyb3d8bbwe Provisioned False
Microsoft.PowerAutomateDesktop 8wekyb3d8bbwe Provisioned False
Microsoft.ScreenSketch 8wekyb3d8bbwe Provisioned False
Microsoft.SecHealthUI 8wekyb3d8bbwe Provisioned True
Microsoft.StorePurchaseApp 8wekyb3d8bbwe Provisioned False
Microsoft.Todos 8wekyb3d8bbwe Provisioned False
Microsoft.UI.Xaml.2.4 8wekyb3d8bbwe Provisioned False
Microsoft.VCLibs.140.00 8wekyb3d8bbwe Provisioned False
Microsoft.VP9VideoExtensions 8wekyb3d8bbwe Provisioned False
Microsoft.WebMediaExtensions 8wekyb3d8bbwe Provisioned False
Microsoft.WebpImageExtension 8wekyb3d8bbwe Provisioned False
Microsoft.Win32WebViewHost cw5n1h2txyewy System True
Microsoft.Windows.Apprep.ChxApp cw5n1h2txyewy System True
Microsoft.Windows.AssignedAccessLockApp cw5n1h2txyewy System True
Microsoft.Windows.CallingShellApp cw5n1h2txyewy System True
Microsoft.Windows.CapturePicker cw5n1h2txyewy System True
Microsoft.Windows.CloudExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.ContentDeliveryManager cw5n1h2txyewy System True
Microsoft.Windows.NarratorQuickStart 8wekyb3d8bbwe System True
Microsoft.Windows.OOBENetworkCaptivePortal cw5n1h2txyewy System True
Microsoft.Windows.OOBENetworkConnectionFlow cw5n1h2txyewy System True
Microsoft.Windows.ParentalControls cw5n1h2txyewy System True
Microsoft.Windows.PeopleExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.Photos 8wekyb3d8bbwe Provisioned False
Microsoft.Windows.PinningConfirmationDialog cw5n1h2txyewy System True
Microsoft.Windows.Search cw5n1h2txyewy System True
Microsoft.Windows.SecureAssessmentBrowser cw5n1h2txyewy System True
Microsoft.Windows.ShellExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.StartMenuExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.XGpuEjectDialog cw5n1h2txyewy System True
Microsoft.WindowsAlarms 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsCalculator 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsCamera 8wekyb3d8bbwe Provisioned False
microsoft.windowscommunicationsapps 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsFeedbackHub 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsMaps 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsNotepad 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsSoundRecorder 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsStore 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsTerminal 8wekyb3d8bbwe Provisioned False
Microsoft.Xbox.TCUI 8wekyb3d8bbwe Provisioned False
Microsoft.XboxGameCallableUI cw5n1h2txyewy System True
Microsoft.XboxGameOverlay 8wekyb3d8bbwe Provisioned False
Microsoft.XboxGamingOverlay 8wekyb3d8bbwe Provisioned False
Microsoft.XboxIdentityProvider 8wekyb3d8bbwe Provisioned False
Microsoft.XboxSpeechToTextOverlay 8wekyb3d8bbwe Provisioned False
Microsoft.YourPhone 8wekyb3d8bbwe Provisioned False
Microsoft.ZuneMusic 8wekyb3d8bbwe Provisioned False
Microsoft.ZuneVideo 8wekyb3d8bbwe Provisioned False
MicrosoftWindows.Client.CBS cw5n1h2txyewy System True
MicrosoftWindows.Client.WebExperience cw5n1h2txyewy Provisioned False
MicrosoftWindows.UndockedDevKit cw5n1h2txyewy System True
NcsiUwpApp 8wekyb3d8bbwe System True
Windows.CBSPreview cw5n1h2txyewy System True
windows.immersivecontrolpanel cw5n1h2txyewy System True
Windows.PrintDialog cw5n1h2txyewy System True

View File

@@ -1,91 +0,0 @@
Name PublisherId Category NonRemovable
---- ----------- -------- ------------
1527c705-839a-4832-9118-54d4Bd6a0c89 cw5n1h2txyewy System True
c5e2524a-ea46-4f67-841f-6a9465d9d515 cw5n1h2txyewy System True
Clipchamp.Clipchamp yxz26nhyzhsrt Provisioned False
E2A4F912-2574-4A75-9BB0-0D023378592B cw5n1h2txyewy System True
F46D4000-FD22-4DB4-AC8E-4E1DDDE828FE cw5n1h2txyewy System True
Microsoft.549981C3F5F10 8wekyb3d8bbwe Provisioned False
Microsoft.AAD.BrokerPlugin cw5n1h2txyewy System True
Microsoft.AccountsControl cw5n1h2txyewy System True
Microsoft.AsyncTextService 8wekyb3d8bbwe System True
Microsoft.BingNews 8wekyb3d8bbwe Provisioned False
Microsoft.BingWeather 8wekyb3d8bbwe Provisioned False
Microsoft.BioEnrollment cw5n1h2txyewy System True
Microsoft.CredDialogHost cw5n1h2txyewy System True
Microsoft.DesktopAppInstaller 8wekyb3d8bbwe Provisioned True
Microsoft.ECApp 8wekyb3d8bbwe System True
Microsoft.GamingApp 8wekyb3d8bbwe Provisioned False
Microsoft.GetHelp 8wekyb3d8bbwe Provisioned False
Microsoft.Getstarted 8wekyb3d8bbwe Provisioned False
Microsoft.HEIFImageExtension 8wekyb3d8bbwe Provisioned False
Microsoft.HEVCVideoExtension 8wekyb3d8bbwe Provisioned False
Microsoft.LockApp cw5n1h2txyewy System True
Microsoft.MicrosoftEdge 8wekyb3d8bbwe System True
Microsoft.MicrosoftEdge.Stable 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftEdgeDevToolsClient 8wekyb3d8bbwe System True
Microsoft.MicrosoftOfficeHub 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftSolitaireCollection 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftStickyNotes 8wekyb3d8bbwe Provisioned False
Microsoft.Paint 8wekyb3d8bbwe Provisioned False
Microsoft.People 8wekyb3d8bbwe Provisioned False
Microsoft.PowerAutomateDesktop 8wekyb3d8bbwe Provisioned False
Microsoft.RawImageExtension 8wekyb3d8bbwe Provisioned False
Microsoft.ScreenSketch 8wekyb3d8bbwe Provisioned False
Microsoft.SecHealthUI 8wekyb3d8bbwe Provisioned True
Microsoft.StorePurchaseApp 8wekyb3d8bbwe Provisioned False
Microsoft.Todos 8wekyb3d8bbwe Provisioned False
Microsoft.VCLibs.140.00 8wekyb3d8bbwe Provisioned False
Microsoft.VP9VideoExtensions 8wekyb3d8bbwe Provisioned False
Microsoft.WebMediaExtensions 8wekyb3d8bbwe Provisioned False
Microsoft.WebpImageExtension 8wekyb3d8bbwe Provisioned False
Microsoft.Win32WebViewHost cw5n1h2txyewy System True
Microsoft.Windows.Apprep.ChxApp cw5n1h2txyewy System True
Microsoft.Windows.AssignedAccessLockApp cw5n1h2txyewy System True
Microsoft.Windows.CallingShellApp cw5n1h2txyewy System True
Microsoft.Windows.CapturePicker cw5n1h2txyewy System True
Microsoft.Windows.CloudExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.ContentDeliveryManager cw5n1h2txyewy System True
Microsoft.Windows.NarratorQuickStart 8wekyb3d8bbwe System True
Microsoft.Windows.OOBENetworkCaptivePortal cw5n1h2txyewy System True
Microsoft.Windows.OOBENetworkConnectionFlow cw5n1h2txyewy System True
Microsoft.Windows.ParentalControls cw5n1h2txyewy System True
Microsoft.Windows.PeopleExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.Photos 8wekyb3d8bbwe Provisioned False
Microsoft.Windows.PinningConfirmationDialog cw5n1h2txyewy System True
Microsoft.Windows.PrintQueueActionCenter cw5n1h2txyewy System True
Microsoft.Windows.SecureAssessmentBrowser cw5n1h2txyewy System True
Microsoft.Windows.ShellExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.StartMenuExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.XGpuEjectDialog cw5n1h2txyewy System True
Microsoft.WindowsAlarms 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsCalculator 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsCamera 8wekyb3d8bbwe Provisioned False
microsoft.windowscommunicationsapps 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsFeedbackHub 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsMaps 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsNotepad 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsSoundRecorder 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsStore 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsTerminal 8wekyb3d8bbwe Provisioned False
Microsoft.Xbox.TCUI 8wekyb3d8bbwe Provisioned False
Microsoft.XboxGameCallableUI cw5n1h2txyewy System True
Microsoft.XboxGameOverlay 8wekyb3d8bbwe Provisioned False
Microsoft.XboxGamingOverlay 8wekyb3d8bbwe Provisioned False
Microsoft.XboxIdentityProvider 8wekyb3d8bbwe Provisioned False
Microsoft.XboxSpeechToTextOverlay 8wekyb3d8bbwe Provisioned False
Microsoft.YourPhone 8wekyb3d8bbwe Provisioned False
Microsoft.ZuneMusic 8wekyb3d8bbwe Provisioned False
Microsoft.ZuneVideo 8wekyb3d8bbwe Provisioned False
MicrosoftCorporationII.QuickAssist 8wekyb3d8bbwe Provisioned False
MicrosoftWindows.Client.CBS cw5n1h2txyewy System True
MicrosoftWindows.Client.Core cw5n1h2txyewy System True
MicrosoftWindows.Client.WebExperience cw5n1h2txyewy Provisioned False
MicrosoftWindows.UndockedDevKit cw5n1h2txyewy System True
NcsiUwpApp 8wekyb3d8bbwe System True
Windows.CBSPreview cw5n1h2txyewy System True
windows.immersivecontrolpanel cw5n1h2txyewy System True
Windows.PrintDialog cw5n1h2txyewy System True

View File

@@ -1,91 +0,0 @@
Name PublisherId Category NonRemovable
---- ----------- -------- ------------
1527c705-839a-4832-9118-54d4Bd6a0c89 cw5n1h2txyewy System True
c5e2524a-ea46-4f67-841f-6a9465d9d515 cw5n1h2txyewy System True
Clipchamp.Clipchamp yxz26nhyzhsrt Provisioned False
E2A4F912-2574-4A75-9BB0-0D023378592B cw5n1h2txyewy System True
F46D4000-FD22-4DB4-AC8E-4E1DDDE828FE cw5n1h2txyewy System True
Microsoft.549981C3F5F10 8wekyb3d8bbwe Provisioned False
Microsoft.AAD.BrokerPlugin cw5n1h2txyewy System True
Microsoft.AccountsControl cw5n1h2txyewy System True
Microsoft.AsyncTextService 8wekyb3d8bbwe System True
Microsoft.BingNews 8wekyb3d8bbwe Provisioned False
Microsoft.BingWeather 8wekyb3d8bbwe Provisioned False
Microsoft.BioEnrollment cw5n1h2txyewy System True
Microsoft.CredDialogHost cw5n1h2txyewy System True
Microsoft.DesktopAppInstaller 8wekyb3d8bbwe Provisioned True
Microsoft.ECApp 8wekyb3d8bbwe System True
Microsoft.GamingApp 8wekyb3d8bbwe Provisioned False
Microsoft.GetHelp 8wekyb3d8bbwe Provisioned False
Microsoft.Getstarted 8wekyb3d8bbwe Provisioned False
Microsoft.HEIFImageExtension 8wekyb3d8bbwe Provisioned False
Microsoft.HEVCVideoExtension 8wekyb3d8bbwe Provisioned False
Microsoft.LockApp cw5n1h2txyewy System True
Microsoft.MicrosoftEdge.Stable 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftEdgeDevToolsClient 8wekyb3d8bbwe System True
Microsoft.MicrosoftOfficeHub 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftSolitaireCollection 8wekyb3d8bbwe Provisioned False
Microsoft.MicrosoftStickyNotes 8wekyb3d8bbwe Provisioned False
Microsoft.Paint 8wekyb3d8bbwe Provisioned False
Microsoft.People 8wekyb3d8bbwe Provisioned False
Microsoft.PowerAutomateDesktop 8wekyb3d8bbwe Provisioned False
Microsoft.RawImageExtension 8wekyb3d8bbwe Provisioned False
Microsoft.ScreenSketch 8wekyb3d8bbwe Provisioned False
Microsoft.SecHealthUI 8wekyb3d8bbwe Provisioned True
Microsoft.StorePurchaseApp 8wekyb3d8bbwe Provisioned False
Microsoft.Todos 8wekyb3d8bbwe Provisioned False
Microsoft.VCLibs.140.00 8wekyb3d8bbwe Provisioned False
Microsoft.VP9VideoExtensions 8wekyb3d8bbwe Provisioned False
Microsoft.WebMediaExtensions 8wekyb3d8bbwe Provisioned False
Microsoft.WebpImageExtension 8wekyb3d8bbwe Provisioned False
Microsoft.Win32WebViewHost cw5n1h2txyewy System True
Microsoft.Windows.Apprep.ChxApp cw5n1h2txyewy System True
Microsoft.Windows.AssignedAccessLockApp cw5n1h2txyewy System True
Microsoft.Windows.CallingShellApp cw5n1h2txyewy System True
Microsoft.Windows.CapturePicker cw5n1h2txyewy System True
Microsoft.Windows.CloudExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.ContentDeliveryManager cw5n1h2txyewy System True
Microsoft.Windows.NarratorQuickStart 8wekyb3d8bbwe System True
Microsoft.Windows.OOBENetworkCaptivePortal cw5n1h2txyewy System True
Microsoft.Windows.OOBENetworkConnectionFlow cw5n1h2txyewy System True
Microsoft.Windows.ParentalControls cw5n1h2txyewy System True
Microsoft.Windows.PeopleExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.Photos 8wekyb3d8bbwe Provisioned False
Microsoft.Windows.PinningConfirmationDialog cw5n1h2txyewy System True
Microsoft.Windows.PrintQueueActionCenter cw5n1h2txyewy System True
Microsoft.Windows.SecureAssessmentBrowser cw5n1h2txyewy System True
Microsoft.Windows.ShellExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.StartMenuExperienceHost cw5n1h2txyewy System True
Microsoft.Windows.XGpuEjectDialog cw5n1h2txyewy System True
Microsoft.WindowsAlarms 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsCalculator 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsCamera 8wekyb3d8bbwe Provisioned False
microsoft.windowscommunicationsapps 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsFeedbackHub 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsMaps 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsNotepad 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsSoundRecorder 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsStore 8wekyb3d8bbwe Provisioned False
Microsoft.WindowsTerminal 8wekyb3d8bbwe Provisioned False
Microsoft.Xbox.TCUI 8wekyb3d8bbwe Provisioned False
Microsoft.XboxGameCallableUI cw5n1h2txyewy System True
Microsoft.XboxGameOverlay 8wekyb3d8bbwe Provisioned False
Microsoft.XboxGamingOverlay 8wekyb3d8bbwe Provisioned False
Microsoft.XboxIdentityProvider 8wekyb3d8bbwe Provisioned False
Microsoft.XboxSpeechToTextOverlay 8wekyb3d8bbwe Provisioned False
Microsoft.YourPhone 8wekyb3d8bbwe Provisioned False
Microsoft.ZuneMusic 8wekyb3d8bbwe Provisioned False
Microsoft.ZuneVideo 8wekyb3d8bbwe Provisioned False
MicrosoftCorporationII.QuickAssist 8wekyb3d8bbwe Provisioned False
MicrosoftWindows.Client.CBS cw5n1h2txyewy System True
MicrosoftWindows.Client.Core cw5n1h2txyewy System True
MicrosoftWindows.Client.FileExp cw5n1h2txyewy System True
MicrosoftWindows.Client.WebExperience cw5n1h2txyewy Provisioned False
MicrosoftWindows.UndockedDevKit cw5n1h2txyewy System True
NcsiUwpApp 8wekyb3d8bbwe System True
Windows.CBSPreview cw5n1h2txyewy System True
windows.immersivecontrolpanel cw5n1h2txyewy System True
Windows.PrintDialog cw5n1h2txyewy System True

View File

@@ -1,46 +0,0 @@
# Research on Windows
In this section, we maintain a structured approach to our research on Windows.
The use of `01` prefixed file names aids in organizing and retrieving search results effectively.
## Apps
The PowerShell script below serves as a method for gathering detailed information about Windows packages.
```ps1
$allPackages = @()
$provisionedPackages = Get-AppxProvisionedPackage -Online
foreach ($installedPackage in Get-AppxPackage -AllUsers) {
if ($installedPackage.IsFramework -eq $true) {
continue
}
$allPackages += [PSCustomObject]@{
Name = $installedPackage.Name
PublisherId = $installedPackage.PublisherId
Category = if ($installedPackage.SignatureKind -eq "System") {
'System'
} elseif ($provisionedPackages | Where-Object { $_.DisplayName -eq $installedPackage.Name }) {
'Provisioned'
} else {
'Installed'
}
NonRemovable = $installedPackage.NonRemovable
}
}
foreach ($provisionedPackage in $provisionedPackages) {
if ($allPackages | Where-Object { $_.Name -eq $provisionedPackage.DisplayName }) {
continue
}
$allPackages += [PSCustomObject]@{
Name = $provisionedPackage.DisplayName
PublisherId = $provisionedPackage.PackageName -split '_' | Select-Object -Last 1
Category = 'Provisioned'
NonRemovable = $false
}
}
$allPackages `
| Sort-Object Name `
| Select-Object Name, PublisherId, Category, NonRemovable `
| Format-Table `
| Out-File -FilePath "$([System.Environment]::GetFolderPath('Desktop'))\apps.txt"
```

View File

@@ -1,58 +0,0 @@
# privacy.sexy Script Guidelines
Create a script for privacy.sexy by submitting a PR or creating an issue (details in [Extend Scripts](./../CONTRIBUTING.md#extend-scripts)).
As scripts are central to privacy.sexy and reach a global audience, their design is critical.
Key attributes of a good script:
- ✅ Well-referenced [documentation](#documentation).
- ✅ Utilizes [shared functions](#shared-functions).
- ✅ Has a [simple name](#name).
## Name
- Choose a title that is easy to understand for all users, regardless of technical skill, yet remains technically accurate.
- Focus on privacy implications, avoiding complex or overly technical jargon.
- Maintain consistency in naming, avoiding linguistic variations.
- Use action-oriented language for clarity and directness. Use an instruction format like "do this, do that" for clear, direct guidance.
- Respect the official casing of brand names.
- Choose clear and uncomplicated language.
- It should start with an imperative noun.
- Start with action verbs like `Clear`, `Disable`, `Remove`, `Configure`, `Minimize`, `Maximize`. While exceptions exist, these prefixes help maintain naming consistency.
- The scripts that modify hosts file should start with `Block ..`.
- Favor the terms:
- `Disable` over `Turn off`, `Stop`, `Prevent`
- `Configure` over `Set up`
- `Clear` over `Erase`, `Clean`
- `Minimize` over `Limit`, `Reduce`
- `Maximize` over `Extend`, `Delay`, `Postpone`, `Prolong`
- `Remove` over `Uninstall`
- `Improve` over `Increase`
- Structure your phrases for clarity, examples:
- Prefer `Disable XX telemetry` over `Disable telemetry in XX`
- Prefer `Clear XX data` over `Clear data from XX`, or `Clear data of XX`.
- Use sentence case rather than Title Case.
## Documentation
- Use credible and reputable sources for references.
- Use archived links by using [archive.org](https://archive.org) or [archive.ph](https://archive.ph).
- Format archive.today links fully, for example: `https://archive.ph/YYYYMMDDhhmmss/https://privacy.sexy`.
- Explain the default behavior if the script is not executed.
## Shared functions
Use existing shared functions when possible, like `DisableService` for disabling services,.
- 📖 Learn about templates in [templating.md](./templating.md).
- 📖 For syntax, see [collection-files.md](collection-files.md).
## Code
- Prefer [shared functions](#shared-functions); avoid custom code unless necessary.
- Keep code simple and compatible with older systems.
- Focus on reliability, ensuring the script is error-resistant, works on different locales and handles unexpected situations.
- Language selection:
- Windows: Use batch when simpler, otherwise PowerShell.
- macOS/Linux: Use bash when simpler, otherwise Python.
- Provide revert code to restore original/default settings when applicable.

View File

@@ -2,142 +2,79 @@
## Benefits of templating ## Benefits of templating
- **Code sharing:** Share code across scripts for consistent practices and easier maintenance. - Generating scripts by sharing code to increase best-practice usage and maintainability.
- **Script independence:** Generate self-contained scripts, eliminating the need for external code. - Creating self-contained scripts without cross-dependencies.
- **Cleaner code:** Use pipes for complex operations, resulting in more readable and streamlined code. - Use of pipes for writing cleaner code and letting pipes do dirty work.
## Expressions ## Expressions
**Syntax:** - Expressions start and end with mustaches (double brackets, `{{` and `}}`).
- E.g. `Hello {{ $name }} !`
- Syntax is close to [Go Templates ❤️](https://pkg.go.dev/text/template) but not the same.
- Functions enables usage of expressions.
- In script definition parts of a function, see [`Function`](./collection-files.md#Function).
- When doing a call as argument values, see [`FunctionCall`](./collection-files.md#Function).
- Expressions inside expressions (nested templates) are supported.
- An expression can output another expression that will also be compiled.
- E.g. following would compile first [with expression](#with), and then [parameter substitution](#parameter-substitution) in its output.
Expressions are enclosed within `{{` and `}}`. ```go
Example: `Hello {{ $name }}!`. {{ with $condition }}
They are a core component of templating, enhancing scripts with dynamic capabilities and functionality. echo {{ $text }}
{{ end }}
**Syntax similarity:** ```
The syntax shares similarities with [Go Templates ❤️](https://pkg.go.dev/text/template), but with some differences:
**Function definitions:**
You can use expressions in function definition.
Refer to [Function](./collection-files.md#function) for more details.
Example usage:
```yaml
name: GreetFunction
parameters:
- name: name
code: Hello {{ $name }}!
```
If you assign `name` the value `world`, invoking `GreetFunction` would result in `Hello world!`.
**Function arguments:**
You can also use expressions in arguments in nested function calls.
Refer to [`Function | collection-files.md`](./collection-files.md#functioncall) for more details.
Example with nested function calls:
```yaml
-
name: PrintMessageFunction
parameters:
- name: message
code: echo "{{ $message }}"
-
name: GreetUserFunction
parameters:
- name: userName
call:
name: PrintMessageFunction
parameters:
argument: 'Hello, {{ $userName }}!'
```
Here, if `userName` is `Alice`, invoking `GreetUserFunction` would execute `echo "Hello, Alice!"`.
**Nested templates:**
You can nest expressions inside expressions (also called "nested templates").
This means that an expression can output another expression where compiler will compile both.
For example, following would compile first [with expression](#with), and then [parameter substitution](#parameter-substitution) in its output:
```go
{{ with $condition }}
echo {{ $text }}
{{ end }}
```
### Parameter substitution ### Parameter substitution
Parameter substitution dynamically replaces variable references with their corresponding values in the script. A simple function example:
**Example function:**
```yaml ```yaml
name: DisplayTextFunction function: EchoArgument
parameters: parameters:
- name: 'text' - name: 'argument'
code: echo {{ $text }} code: Hello {{ $argument }} !
``` ```
Invoking `DisplayTextFunction` with `text` set to `"Hello, world!"` would result in `echo "Hello, World!"`. It would print "Hello world" if it's called in a [script](./collection-files.md#script) as following:
```yaml
script: Echo script
call:
function: EchoArgument
parameters:
argument: World
```
A function can call other functions such as:
```yaml
-
function: CallerFunction
parameters:
- name: 'value'
call:
function: EchoArgument
parameters:
argument: {{ $value }}
-
function: EchoArgument
parameters:
- name: 'argument'
code: Hello {{ $argument }} !
```
### with ### with
The `with` expression enables conditional rendering and provides a context variable for simpler code. Skips its "block" if the variable is absent or empty. Its "block" is between `with` start (`{{ with .. }}`) and end (`{{ end }`}) expressions.
E.g. `{{ with $parameterName }} Hi, I'm a block! {{ end }}` would only output `Hi, I'm a block!` if `parameterName` has any value..
**Optional block rendering:** It binds its context (value of the provided parameter value) as arbitrary `.` value. It allows you to use the argument value of the given parameter when it is provided and not empty such as:
If the provided variable is falsy (`false`, `null`, or empty), the compiler skips the enclosed block of code.
A "block" lies between the with start (`{{ with .. }}`) and end (`{{ end }}`) expressions, defining its boundaries.
Example:
```go
{{ with $optionalVariable }}
Hello
{{ end }}
```
This would display `Hello` if `$optionalVariable` is truthy.
**Parameter declaration:**
You should set `optional: true` for the argument if you use it like `{{ with $argument }} .. {{ end }}`.
Declare parameters used for `with` condition as optional such as:
```yaml
name: ConditionalOutputFunction
parameters:
- name: 'data'
optional: true
code: |-
{{ with $data }}
Data is: {{ . }}
{{ end }}
```
**Context variable:**
`with` statement binds its context (value of the provided parameter value) as arbitrary `.` value.
`{{ . }}` syntax gives you access to the context variable.
This is optional to use, and not required to use `with` expressions.
For example:
```go ```go
{{ with $parameterName }}Parameter value is {{ . }} here {{ end }} {{ with $parameterName }}Parameter value is {{ . }} here {{ end }}
``` ```
**Multiline text:** It supports multiline text inside the block. You can have something like:
It supports multiline text inside the block. You can write something like:
```go ```go
{{ with $argument }} {{ with $argument }}
@@ -146,9 +83,7 @@ It supports multiline text inside the block. You can write something like:
{{ end }} {{ end }}
``` ```
**Inner expressions:** You can also use other expressions inside its block, such as [parameter substitution](#parameter-substitution):
You can also embed other expressions inside its block, such as [parameter substitution](#parameter-substitution):
```go ```go
{{ with $condition }} {{ with $condition }}
@@ -156,44 +91,32 @@ You can also embed other expressions inside its block, such as [parameter substi
{{ end }} {{ end }}
``` ```
This also includes nesting `with` statements: 💡 Declare parameters used for `with` condition as optional. Set `optional: true` for the argument if you use it like `{{ with $argument }} .. {{ end }}`.
```go Example:
{{ with $condition1 }}
Value of $condition1: {{ . }} ```yaml
{{ with $condition2 }} function: FunctionThatOutputsConditionally
Value of $condition2: {{ . }} parameters:
- name: 'argument'
optional: true
code: |-
{{ with $argument }}
Value is: {{ . }}
{{ end }} {{ end }}
{{ end }}
``` ```
### Pipes ### Pipes
Pipes are functions designed for text manipulation. - Pipes are functions available for handling text.
They allow for a sequential application of operations resembling [Unix pipelines](https://en.wikipedia.org/wiki/Pipeline_(Unix)), also known as "chaining". - Allows stacking actions one after another also known as "chaining".
Each pipeline's output becomes the input of the following pipe. - Like [Unix pipelines](https://en.wikipedia.org/wiki/Pipeline_(Unix)), the concept is simple: each pipeline's output becomes the input of the following pipe.
- You cannot create pipes. [A dedicated compiler](./application.md#parsing-and-compiling) provides pre-defined pipes to consume in collection files.
**Pre-defined**: - You can combine pipes with other expressions such as [parameter substitution](#parameter-substitution) and [with](#with) syntax.
- ❗ Pipe names must be camelCase without any space or special characters.
Pipes are pre-defined by the system. - **Existing pipes**
You cannot create pipes in [collection files](./collection-files.md). - `inlinePowerShell`: Converts a multi-lined PowerShell script to a single line.
[A dedicated compiler](./application.md#parsing-and-compiling) provides pre-defined pipes to consume in collection files. - `escapeDoubleQuotes`: Escapes `"` characters, allows you to use them inside double quotes (`"`).
- **Example usages**
**Compatibility:** - `{{ with $code }} echo "{{ . | inlinePowerShell }}" {{ end }}`
- `{{ with $code }} echo "{{ . | inlinePowerShell | escapeDoubleQuotes }}" {{ end }}`
You can combine pipes with other expressions such as [parameter substitution](#parameter-substitution) and [with](#with) syntax.
For example:
```go
{{ with $script }} echo "{{ . | inlinePowerShell | escapeDoubleQuotes }}" {{ end }}
```
**Naming:**
❗ Pipe names must be camelCase without any space or special characters.
**Available pipes:**
- `inlinePowerShell`: Converts a multi-lined PowerShell script to a single line.
- `escapeDoubleQuotes`: Escapes `"` characters for batch command execution, allows you to use them inside double quotes (`"`).

View File

@@ -29,9 +29,7 @@ There are different types of tests executed:
- Evaluate individual components in isolation. - Evaluate individual components in isolation.
- Located in [`./tests/unit`](./../tests/unit). - Located in [`./tests/unit`](./../tests/unit).
- Achieve isolation using stubs where you place: - Achieve isolation using [stubs](./../tests/unit/shared/Stubs).
- Common stubs in [`./shared/Stubs`](./../tests/unit/shared/Stubs),
- Component-specific stubs in same folder as test file.
- Include Vue component tests, enabled by `@vue/test-utils`. - Include Vue component tests, enabled by `@vue/test-utils`.
#### Unit tests naming #### Unit tests naming
@@ -70,23 +68,21 @@ These checks validate various qualities like runtime execution, building process
- [`./src/`](./../src/): Contains the code subject to testing. - [`./src/`](./../src/): Contains the code subject to testing.
- [`./tests/shared/`](./../tests/shared/): Contains code shared by different test categories. - [`./tests/shared/`](./../tests/shared/): Contains code shared by different test categories.
- [`bootstrap/setup.ts`](./../tests/shared/bootstrap/setup.ts): Initializes unit and integration tests. - [`bootstrap/setup.ts`](./../tests/shared/bootstrap/setup.ts): Initializes unit and integration tests.
- [`Assertions/`](./../tests/shared/Assertions/): Contains common assertion functions, prefixed with `expect`.
- [`./tests/unit/`](./../tests/unit/) - [`./tests/unit/`](./../tests/unit/)
- Stores unit test code. - Stores unit test code.
- The directory structure mirrors [`./src/`](./../src). - The directory structure mirrors [`./src/`](./../src).
- E.g., tests for [`./src/application/ApplicationFactory.ts`](./../src/application/ApplicationFactory.ts) reside in [`./tests/unit/application/ApplicationFactory.spec.ts`](./../tests/unit/application/ApplicationFactory.spec.ts). - E.g., tests for [`./src/application/ApplicationFactory.ts`](./../src/application/ApplicationFactory.ts) reside in [`./tests/unit/application/ApplicationFactory.spec.ts`](./../tests/unit/application/ApplicationFactory.spec.ts).
- [`shared/`](./../tests/unit/shared/) - [`shared/`](./../tests/unit/shared/)
- Contains shared unit test functionalities. - Contains shared unit test functionalities.
- [`Assertions/`](./../tests/unit/shared/Assertions): Contains common assertion functions, prefixed with `expect`.
- [`TestCases/`](./../tests/unit/shared/TestCases/) - [`TestCases/`](./../tests/unit/shared/TestCases/)
- Shared test cases. - Shared test cases.
- Functions that calls `it()` from [Vitest](https://vitest.dev/) should have `it` prefix. - Functions that calls `it()` from [Vitest](https://vitest.dev/) should have `it` prefix.
- [`Stubs/`](./../tests/unit/shared/Stubs): Maintains stubs for component isolation, equipped with basic functionalities and, when necessary, spying or mocking capabilities. - [`Stubs/`](./../tests/unit/shared/Stubs): Maintains stubs for component isolation, equipped with basic functionalities and, when necessary, spying or mocking capabilities.
- [`./tests/integration/`](./../tests/integration/): Contains integration test files. - [`./tests/integration/`](./../tests/integration/): Contains integration test files.
- [`cypress.config.ts`](./../cypress.config.ts): Cypress (E2E tests) configuration file. - [`cypress.config.ts`](./../cypress.config.ts): Cypress (E2E tests) configuration file.
- [`cypress-dirs.json`](./../cypress-dirs.json): A central definition of directories used by Cypress, designed for reuse across different configurations.
- [`./tests/e2e/`](./../tests/e2e/): Base Cypress folder, includes tests with `.cy.ts` extension. - [`./tests/e2e/`](./../tests/e2e/): Base Cypress folder, includes tests with `.cy.ts` extension.
- [`/support/e2e.ts`](./../tests/e2e/support/e2e.ts): Support file, runs before every single spec file.
- [`/tsconfig.json`]: TypeScript configuration for file Cypress code, improves IDE support, recommended to have by official documentation. - [`/tsconfig.json`]: TypeScript configuration for file Cypress code, improves IDE support, recommended to have by official documentation.
- *(git ignored)* `/videos`: Asset folder for videos taken during tests. - *(git ignored)* `/videos`: Asset folder for videos taken during tests.
- *(git ignored)* `/screenshots`: Asset folder for Screenshots taken during tests. - *(git ignored)* `/screenshots`: Asset folder for Screenshots taken during tests.
- [`/support/e2e.ts`](./../tests/e2e/support/e2e.ts): Support file, runs before every single test file.
- [`/support/interactions/`](./../tests/e2e/support/interactions/): Contains reusable functions for simulating user interactions, enhancing test readability and maintainability.

View File

@@ -1,13 +1,8 @@
/* eslint-disable no-template-curly-in-string */ /* eslint-disable no-template-curly-in-string */
const { join, resolve } = require('node:path'); const { join } = require('path');
const { readdirSync, existsSync } = require('node:fs');
const { electronBundled, electronUnbundled } = require('./dist-dirs.json'); const { electronBundled, electronUnbundled } = require('./dist-dirs.json');
/**
* @type {import('electron-builder').Configuration}
* @see https://www.electron.build/configuration/configuration
*/
module.exports = { module.exports = {
// Common options // Common options
publish: { publish: {
@@ -17,12 +12,9 @@ module.exports = {
}, },
directories: { directories: {
output: electronBundled, output: electronBundled,
buildResources: resolvePathFromProjectRoot('src/presentation/electron/build'),
}, },
extraMetadata: { extraMetadata: {
main: findMainEntryFile( main: join(electronUnbundled, 'main/index.cjs'), // do not `path.resolve`, it expects a relative path
join(electronUnbundled, 'main'), // do not `path.resolve`, it expects a relative path
),
}, },
// Windows // Windows
@@ -43,32 +35,9 @@ module.exports = {
// macOS // macOS
mac: { mac: {
target: { target: 'dmg',
target: 'dmg',
arch: 'universal',
},
}, },
dmg: { dmg: {
artifactName: '${name}-${version}.${ext}', artifactName: '${name}-${version}.${ext}',
}, },
}; };
/**
* Finds by accommodating different JS file extensions and module formats.
*/
function findMainEntryFile(parentDirectory) {
const absoluteParentDirectory = resolvePathFromProjectRoot(parentDirectory);
if (!existsSync(absoluteParentDirectory)) {
return null; // Avoid disrupting other processes such `npm install`.
}
const files = readdirSync(absoluteParentDirectory);
const entryFile = files.find((file) => /^index\.(cjs|mjs|js)$/.test(file));
if (!entryFile) {
throw new Error(`Main entry file not found in ${absoluteParentDirectory}.`);
}
return join(parentDirectory, entryFile);
}
function resolvePathFromProjectRoot(pathSegment) {
return resolve(__dirname, pathSegment);
}

View File

@@ -1,28 +1,22 @@
import { resolve } from 'node:path'; import { resolve } from 'path';
import { mergeConfig, type UserConfig } from 'vite'; import { mergeConfig, UserConfig } from 'vite';
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'; import { defineConfig, externalizeDepsPlugin } from 'electron-vite';
import { getAliases, getClientEnvironmentVariables } from './vite-config-helper'; import { getAliasesFromTsConfig, getClientEnvironmentVariables } from './vite-config-helper';
import { createVueConfig } from './vite.config'; import { createVueConfig } from './vite.config';
import distDirs from './dist-dirs.json' assert { type: 'json' }; import distDirs from './dist-dirs.json' assert { type: 'json' };
const MAIN_ENTRY_FILE = resolvePathFromProjectRoot('src/presentation/electron/main/index.ts'); const MAIN_ENTRY_FILE = resolvePathFromProjectRoot('src/presentation/electron/main/index.ts');
const PRELOAD_ENTRY_FILE = resolvePathFromProjectRoot('src/presentation/electron/preload/index.ts'); const PRELOAD_ENTRY_FILE = resolvePathFromProjectRoot('src/presentation/electron/preload/index.ts');
const WEB_INDEX_HTML_PATH = resolvePathFromProjectRoot('src/presentation/index.html'); const WEB_INDEX_HTML_PATH = resolvePathFromProjectRoot('src/presentation/index.html');
const ELECTRON_DIST_SUBDIRECTORIES = { const DIST_DIR = resolvePathFromProjectRoot(distDirs.electronUnbundled);
main: resolveElectronDistSubdirectory('main'),
preload: resolveElectronDistSubdirectory('preload'),
renderer: resolveElectronDistSubdirectory('renderer'),
};
process.env.ELECTRON_ENTRY = resolve(ELECTRON_DIST_SUBDIRECTORIES.main, 'index.mjs');
export default defineConfig({ export default defineConfig({
main: getSharedElectronConfig({ main: getSharedElectronConfig({
distDirSubfolder: ELECTRON_DIST_SUBDIRECTORIES.main, distDirSubfolder: 'main',
entryFilePath: MAIN_ENTRY_FILE, entryFilePath: MAIN_ENTRY_FILE,
}), }),
preload: getSharedElectronConfig({ preload: getSharedElectronConfig({
distDirSubfolder: ELECTRON_DIST_SUBDIRECTORIES.preload, distDirSubfolder: 'preload',
entryFilePath: PRELOAD_ENTRY_FILE, entryFilePath: PRELOAD_ENTRY_FILE,
}), }),
renderer: mergeConfig( renderer: mergeConfig(
@@ -31,7 +25,7 @@ export default defineConfig({
}), }),
{ {
build: { build: {
outDir: ELECTRON_DIST_SUBDIRECTORIES.renderer, outDir: resolve(DIST_DIR, 'renderer'),
rollupOptions: { rollupOptions: {
input: { input: {
index: WEB_INDEX_HTML_PATH, index: WEB_INDEX_HTML_PATH,
@@ -48,45 +42,28 @@ function getSharedElectronConfig(options: {
}): UserConfig { }): UserConfig {
return { return {
build: { build: {
outDir: options.distDirSubfolder, outDir: resolve(DIST_DIR, options.distDirSubfolder),
lib: { lib: {
entry: options.entryFilePath, entry: options.entryFilePath,
}, },
rollupOptions: { rollupOptions: {
output: { output: {
format: 'es', entryFileNames: '[name].cjs', // This is needed so `type="module"` works
// Ensure all generated files use '.mjs' for module consistency.
// Otherwise, preloader process get `.mjs` extension but main process get `.js` extension, see https://github.com/alex8088/electron-vite/issues/397.
entryFileNames: '[name].mjs',
}, },
}, },
}, },
plugins: [externalizeDepsPlugin({ plugins: [externalizeDepsPlugin()],
exclude: [
// Keep 'electron-log' in bundling process.
// This is a workaround for inability of Electron's ESM loader to resolve subpath imports.
// Do not externalize `electron-log` so subpath imports such as `electron-log/main` works.
// See https://github.com/electron/electron/issues/41241, https://github.com/alex8088/electron-vite/issues/401
'electron-log',
],
})],
define: { define: {
...getClientEnvironmentVariables(), ...getClientEnvironmentVariables(),
}, },
resolve: { resolve: {
alias: { alias: {
...getAliases(), ...getAliasesFromTsConfig(),
}, },
}, },
}; };
} }
function resolvePathFromProjectRoot(pathSegment: string): string { function resolvePathFromProjectRoot(pathSegment: string) {
return resolve(__dirname, pathSegment); return resolve(__dirname, pathSegment);
} }
function resolveElectronDistSubdirectory(subDirectory: string): string {
const electronDistDir = resolvePathFromProjectRoot(distDirs.electronUnbundled);
return resolve(electronDistDir, subDirectory);
}

View File

@@ -0,0 +1 @@
<mxfile host="Electron" modified="2021-01-31T12:32:01.751Z" agent="5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/14.1.8 Chrome/87.0.4280.88 Electron/11.1.1 Safari/537.36" etag="OTbSPW1ZOLwiPL6mt-j9" version="14.1.8" type="device"><diagram id="rhL8jzEM8kVVyiS98U7u" name="Page-1">3VtZd6JKF/01/dhZjA6PREjCXRbGFpM2L70QCYIoLsUI/PpvnwKcMD3cazrJl6wEqfHU3vvsKoz5Infm6e3KWU5ZPPGiL5IwSb/I+hdJUsUmflNBVhQoDaEo8FfBpCgS9wWDIPfKwqrZJph466OGSRxHSbA8LnTjxcJzk6MyZ7WKt8fNnuPoeNal43u1goHrRPXSx2CSTIvSlirsy++8wJ9WM4tCWTN3qsZlwXrqTOLtQZFsfJE7qzhOilfztONFhF2FS9Hv5pXaXWArb5H8Tofr+9ZNO9J+6A+Ljvr89N2aP5tflSq4JKtW7E0AQHkbr5Jp7McLJzL2pdereLOYeDSsgLt9m24cL1EoojD0kiQr2XQ2SYyiaTKPylovDZLv1P1KLe9GBzV6Wo7Mb7LqZpGssoNOdDs6rNt343dVv3WyimdeJ47iFV+f3OZfqKkDWGK6jjcr1/sJapUQnZXvJT9pJxXtCNGDCUp6br147iFSNFh5kZMEL8eSc0rl+rt2e3LxouT3T7iW3oXrHW9HrO1J/IC8yZfmjXfVVisnO2iwjINFsj4Y+Z4K0KD0TrnMzdI51ZP0/nlrSVRPBFNMv5fPbh3/QVHyu7rHgXcIV5L6m/bxeWSofCj7KMd9caJNOdP9yltj8Zg7XtSEcEzzdhok3mDpcFy2OCkcU/ocRNEBxhPVa02Uc+i3pLHcaFCPeJFUOjuzFVbBeqvES38KXlnbaB6nT5lN2/2eL1c7+/Rgv69OMxdHW268Z2qJR6n1m5klHmeW9B6pJb1Xav07h28fm7YoH5n2L9tLzebbm7zc+ixHxPcU1MWPDP/JPaSaV2vLZRS4l7DqI+OtWfezSt/nyGjwr3KEg/Li62ck/b6Lq8cuvnsYO7Rx6YyNN9/MxtXPkjwf6flK/pQHJLmWdHo8d4LLHo3G4mTyfBZ3UWjKbe8Njkbtk6Rq15NKUs4klfpWSaXUgDYXzysHiGzcZLPyLgr4c8v1XPcc4OOWqqjCGwDePDmLNs4A3vqbLtaoAe69eOXJ5hWgxT8H+tlrnAd60myPBeEyO0TrBNtmHdvmGWilt4K2WYN25S3jdZDE5eCfGl75zAb8V+Ft1a3CWCRB8hmxPfWFdwe3XQM3ma48ZxIs/P8DeN/dGsT6KX5Of165rO2OBU/2GufAFbyW0GpdBlwcTo7BFZQ6uOqVeAZe6a3grZ/X8DKY/OoZ6aNCLKniVfvDgazWQF4nTvKzI9qf42vo9H0ZFE9MQKze/XhHCP/K6euSGJ6+mXoORPHcu6lvh2H9mOUcviEiRLEfuJ8HULG+Nf1dQHdr2AOazamXG0eR5xKqH1efHw/N+lZUA289dZb0MpjzTywcQkUrh5QjLQr8BcoSeptoV9p1xl50T48UJHVZH8dJEs/RIKKKa8ed+ZyYowMXfaEJn0xbL4tPVtBBy6lunoOUqLwu49GnSUIfydAICenGnSyUq8CNF88BKF9duZhRusHe6uBC5VDHDZIuXn91FpOv4xV+U5FKh54budH88bDxwvUPaoKDUOtqWZ0pL/pk3aa/UpxyryhXap38fenl6a9vkp+ffvmP6f/qTOKxtxOB1Gr9GDjr9QXpl9TWVVP9PQlI5zUgvZkI6tv85xeB+EsRjBdb/AbFKX7wCtsyFdNbausLsS7LyhHlcuOqVT+QSO0zht9+K7Lr55HPT7bwS7Kf45XvLb6uvZg+TXDTAC83y4C/Z7v+Gi+TYB7k/ER2wZzfvUtSsS/XqK/0cUh9VfZfqH/Y3Hrj5vegr7fv2awhLwLh8cyf5n7J/CWIPS+Z8+Qe8V/RzamUteJWulm/gJzrlM58nfs7S3rKrpXxY7pxcyFw7r4Jrh6/dOWJPMlUmWXqizt3X1iobVmnnU/mbmDeTZZPd9/i+4GZWfYoMG+nkfM4iSe6ELBwKJnBteQ8Psj9eVtBm62paz4v103RCkzMfX/r+k/zaD1Gj/G8vXkamMV9R8wmj2l0P/gnmswfNmPp28wMldZIirKRlEbm7dNyfLttmwHL+uE/N0wwMLtFs6Qs9Om1unt9Z7bN0Mh6HfPlPkwXB33Vb7OH62/hLCjLEnfxsH6yi1i8+UM2zniUd9fTya3vPyFK2zawfkVkuulbubGxwijs2qbUBS7WQBC6oZtbgSBYgSJaobthoZl27SGVSyzQUqujCMweJqhPcfWZrW0se5Z17f6G5SMZ2KDtKLcGGq6mYOpMxb1gzY0MV8nKtOoKPA2fdajdKMOcVC4yiSVWpsiWbSbMZhjbxNgzxDFCHKZIYzEepylYmZAjnhx1PuJRmO6jD9aUz1LiqBsaQq8jpKjLMJZv6RjH9uWubaTd0M+tx3MxaRTTpmcPJawb8/Zlby4kWBvKZqqpu2jLtpbEUo4jxwBz2kOxWLshW4GWsUDJe3bfZ/kM8ZBmGOZkSq+j5bQ+FjJoiWL1wYO76el+jv4y4tiygaaijYR+GBu42po0sk1wxfEtr4hzoG27wIjpmkj4WzraZVgvjU9zow/TXQXrABY+8Qeeh4SJivi2TGcJHz830MYgvMCvoIBrzkcP2Fq8DeFPPDDU9WX0zxnVvcqpkHfDmQAN4DpUvYArdzv6/i02b/ttcyakPYo3NGl9W8xHvFPcWyg+QY5izQblGcadIXcFgc+n+xwP8CsWmhymLBBIu+grEB8CcEW8Ptqwck0zWgv0CDz1IepGGLt/Hs8O8BwoWyuc+Wifs9wKGdeARtio4C4j3Vvh0IfuVHALfg1gPEOsBtbaV0x9RPFluE8pZ4ABrn3oxkQe+FuKE30zWgt+gP1MfY1bU+8Tf9Ay8kDvS6RDi17nlAsjhWvtkdY7pHFIY4h1poInmluxOhrmdIUe8gXYiozj7UNrTCy4nAms0KqAssQKSQt96Jj0MiIfkICpwmwXGoWOwdPrsRJOrgz8ZCt/CLkubZYjZ0n3AmLJMJZq6W5i0Rj5CJgMEYNJmMiESY+0w/EeIUcpTkMs8sYAf8CNuAk06Arj5CbnGXy/ih/4Jx3JRR4b4hkdKtxrMi3t6S7laT7KMa+tCUUu+6RB4lXqwc8QP7h3eU739D7mIe0apPuUUUz6kDREeKo9e5T0qL3OuEYseFGXvIzy5/bVvCFNy/C3jPN2W3ohjYs1kkd0aT2hKUKLaW+gKD3ySfJpvQ//MEhjyG3kAvyD8XgE0qxI8XA/DYeUx7S2DJiCY7STXo0HOsB6uIZd1ZKXCTiBRkzu9z19BLwoj42kyEsT+qdYfLHUYIo4Ea+m0N6CeAXue1inRdjkM65dC+OAb8xtSow8PSM9ukmP+1c/ezVXqd4eCZQnaC+McoPvNSzTuIfhWuwPpF/eZkQ5grWT12jEPfj0aayUv87dpPBt4piwYrTPUR5R/iiv40T+oEHPtA/McuSpCK1k2DtoPInZ/4RYM+FAuSgSLvBZeBe45X7F84G4zfg+m1VtuYbLMu20n1/1IzzIO7G/kW/tvL+o2/Xf9ava0rqrGE777eYF5zx/4Iamfj0lbjAW4uvnZZ7Bi4wyV3gcx/WYAzGU9dcN2+7THqLynON7Vz8d5aSZ4UE8/dN4hAMcgAnXu0px4QwjHuC2679fB28LXWrJHhPe73DMPaaFXgn7Au+BdgbvPTZFjgAdySjXDB/RWbVu0jr5vQLfOq2vtFPUL+Kgmyst9/ZGcDrXM5wcLcxH5wHSqkjnLkv/Fv4Rd3WshDpW7BQr9V9j1flbWGEs7rczn2so9zOce6CxmVLstxo8XeBeWJwrNRWemvL9Jx8mHMP8aQo/ynCu86trNU9RT35J50BXIo/r2eRptNe78B/yf9pvyZ/orGls6ZxSxK3RtYxBK2OqYtCKmIr85vtOEdNTwwxadFLvtBf34fblCUroyniiyRV6hrrMnz8l+Uo9fuNJlurPoY0zz6GNP34Oxe3+v8qKTwHv/zVPNv4H</diagram></mxfile>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

After

Width:  |  Height:  |  Size: 98 KiB

22434
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,12 @@
{ {
"name": "privacy.sexy", "name": "privacy.sexy",
"version": "0.13.6", "version": "0.12.5",
"private": true, "private": true,
"slogan": "Privacy is sexy", "slogan": "Now you have the choice",
"description": "Enforce privacy & security best-practices on Windows, macOS and Linux, because privacy is sexy.", "description": "Enforce privacy & security best-practices on Windows, macOS and Linux, because privacy is sexy 🍑🍆",
"author": "undergroundwires", "author": "undergroundwires",
"type": "module", "type": "module",
"main": "./dist-electron-unbundled/main/index.cjs",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vue-tsc --noEmit && vite build", "build": "vue-tsc --noEmit && vite build",
@@ -14,7 +15,7 @@
"test:integration": "vitest run --dir tests/integration", "test:integration": "vitest run --dir tests/integration",
"test:cy:run": "start-server-and-test \"vite build && vite preview --port 7070\" http://localhost:7070 \"cypress run --config baseUrl=http://localhost:7070\"", "test:cy:run": "start-server-and-test \"vite build && vite preview --port 7070\" http://localhost:7070 \"cypress run --config baseUrl=http://localhost:7070\"",
"test:cy:open": "start-server-and-test \"vite --port 7070 --mode production\" http://localhost:7070 \"cypress open --config baseUrl=http://localhost:7070\"", "test:cy:open": "start-server-and-test \"vite --port 7070 --mode production\" http://localhost:7070 \"cypress open --config baseUrl=http://localhost:7070\"",
"lint": "npm run lint:md && npm run lint:md:consistency && npm run lint:md:relative-urls && npm run lint:md:external-urls && npm run lint:eslint && npm run lint:yaml && npm run lint:pylint", "lint": "npm run lint:md && npm run lint:md:consistency && npm run lint:md:relative-urls && npm run lint:eslint && npm run lint:yaml",
"install-deps": "node scripts/npm-install.js", "install-deps": "node scripts/npm-install.js",
"icons:build": "node scripts/logo-update.js", "icons:build": "node scripts/logo-update.js",
"check:desktop": "vitest run --dir tests/checks/desktop-runtime-errors --environment node", "check:desktop": "vitest run --dir tests/checks/desktop-runtime-errors --environment node",
@@ -24,84 +25,78 @@
"electron:preview": "electron-vite preview", "electron:preview": "electron-vite preview",
"electron:prebuild": "electron-vite build", "electron:prebuild": "electron-vite build",
"electron:build": "electron-builder", "electron:build": "electron-builder",
"lint:eslint": "eslint . --max-warnings=0 --ignore-path .gitignore", "lint:eslint": "eslint . --ignore-path .gitignore",
"lint:md": "markdownlint **/*.md --ignore node_modules", "lint:md": "markdownlint **/*.md --ignore node_modules",
"lint:md:consistency": "remark . --frail --use remark-preset-lint-consistent", "lint:md:consistency": "remark . --frail --use remark-preset-lint-consistent",
"lint:md:relative-urls": "remark . --frail --use remark-validate-links", "lint:md:relative-urls": "remark . --frail --use remark-validate-links",
"lint:md:external-urls": "remark . --frail --use remark-lint-no-dead-urls",
"lint:yaml": "yamllint **/*.yaml --ignore=node_modules/**/*.yaml", "lint:yaml": "yamllint **/*.yaml --ignore=node_modules/**/*.yaml",
"lint:pylint": "pylint **/*.py",
"postinstall": "electron-builder install-app-deps", "postinstall": "electron-builder install-app-deps",
"postuninstall": "electron-builder install-app-deps" "postuninstall": "electron-builder install-app-deps"
}, },
"dependencies": { "dependencies": {
"@floating-ui/vue": "^1.1.1", "@floating-ui/vue": "^1.0.2",
"@juggle/resize-observer": "^3.4.0", "@juggle/resize-observer": "^3.4.0",
"ace-builds": "^1.35.3", "ace-builds": "^1.30.0",
"electron-log": "^5.1.6", "cross-fetch": "^4.0.0",
"electron-progressbar": "^2.2.1", "electron-log": "^4.4.8",
"electron-updater": "^6.2.1", "electron-progressbar": "^2.1.0",
"electron-updater": "^6.1.4",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"markdown-it": "^14.1.0", "markdown-it": "^13.0.2",
"vue": "^3.4.32" "vue": "^2.7.14"
}, },
"devDependencies": { "devDependencies": {
"@modyfi/vite-plugin-yaml": "^1.1.0", "@modyfi/vite-plugin-yaml": "^1.0.4",
"@rushstack/eslint-patch": "^1.10.3", "@rushstack/eslint-patch": "^1.5.1",
"@types/ace": "^0.0.52", "@types/ace": "^0.0.49",
"@types/file-saver": "^2.0.7", "@types/file-saver": "^2.0.5",
"@types/markdown-it": "^14.1.1", "@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/eslint-plugin": "6.21.0", "@typescript-eslint/parser": "^5.62.0",
"@typescript-eslint/parser": "6.21.0", "@vitejs/plugin-legacy": "^4.1.1",
"@vitejs/plugin-legacy": "^5.4.1", "@vitejs/plugin-vue2": "^2.2.0",
"@vitejs/plugin-vue": "^5.0.5", "@vue/eslint-config-airbnb-with-typescript": "^7.0.0",
"@vue/eslint-config-airbnb-with-typescript": "^8.0.0", "@vue/eslint-config-typescript": "^11.0.3",
"@vue/eslint-config-typescript": "12.0.0", "@vue/test-utils": "^1.3.6",
"@vue/test-utils": "^2.4.6", "autoprefixer": "^10.4.16",
"autoprefixer": "^10.4.19", "cypress": "^13.3.1",
"cypress": "^13.13.1", "electron": "^27.0.0",
"electron": "^31.2.1", "electron-builder": "^24.6.4",
"electron-builder": "^24.13.3",
"electron-devtools-installer": "^3.2.0", "electron-devtools-installer": "^3.2.0",
"electron-vite": "^2.3.0", "electron-icon-builder": "^2.0.1",
"eslint": "8.57.0", "electron-vite": "^1.0.27",
"eslint-plugin-cypress": "^3.3.0", "eslint": "^8.51.0",
"eslint-plugin-vue": "^9.27.0", "eslint-plugin-cypress": "^2.15.1",
"eslint-plugin-vuejs-accessibility": "^2.4.0", "eslint-plugin-vue": "^9.17.0",
"jsdom": "^24.1.0", "eslint-plugin-vuejs-accessibility": "^2.2.0",
"markdownlint-cli": "^0.41.0", "icon-gen": "^4.0.0",
"postcss": "^8.4.39", "jsdom": "^22.1.0",
"remark-cli": "^12.0.1", "markdownlint-cli": "^0.37.0",
"remark-lint-no-dead-urls": "^2.0.0", "postcss": "^8.4.31",
"remark-preset-lint-consistent": "^6.0.0", "remark-cli": "^12.0.0",
"remark-validate-links": "^13.0.1", "remark-lint-no-dead-urls": "^1.1.0",
"sass": "~1.79.4", "remark-preset-lint-consistent": "^5.1.2",
"start-server-and-test": "^2.0.4", "remark-validate-links": "^13.0.0",
"terser": "^5.31.3", "sass": "^1.69.3",
"tslib": "^2.6.3", "start-server-and-test": "^2.0.1",
"typescript": "~5.5.4", "svgexport": "^0.4.2",
"vite": "^5.4.8", "terser": "^5.21.0",
"vitest": "^2.0.3", "tslib": "^2.6.2",
"vue-tsc": "^2.0.26", "typescript": "^5.2.2",
"vite": "^4.4.11",
"vitest": "^0.34.6",
"vue-tsc": "^1.8.19",
"yaml-lint": "^1.7.0" "yaml-lint": "^1.7.0"
}, },
"//devDependencies": { "//devDependencies": {
"terser": "Used by `@vitejs/plugin-legacy` for minification", "terser": "Used by @vitejs/plugin-legacy for minification",
"@rushstack/eslint-patch": "Needed by `@vue/eslint-config-typescript` and `@vue/eslint-config-airbnb-with-typescript`", "@rushstack/eslint-patch": "Needed by @vue/eslint-config-typescript",
"@typescript-eslint/eslint-plugin": "Cannot migrate to v7 because of `@vue/eslint-config-airbnb-with-typescript`, see https://github.com/vuejs/eslint-config-airbnb/issues/63", "@vue/eslint-config-typescript": "Cannot upgrade to 12.X.X due to @vue/eslint-config-airbnb-with-typescript, https://github.com/vuejs/eslint-config-airbnb/issues/58",
"@typescript-eslint/parser": "Cannot migrate to v7 because of `@vue/eslint-config-airbnb-with-typescript`, see https://github.com/vuejs/eslint-config-airbnb/issues/63", "@typescript-eslint/eslint-plugin": "Cannot upgrade to 6.X.X due to @vue/eslint-config-airbnb-with-typescript, https://github.com/vuejs/eslint-config-airbnb/issues/58",
"@vue/eslint-config-typescript": "Cannot migrate to v13 because of `@vue/eslint-config-airbnb-with-typescript`, see https://github.com/vuejs/eslint-config-airbnb/issues/63", "@typescript-eslint/parser": "Cannot upgrade to 6.X.X due to @vue/eslint-config-airbnb-with-typescript, https://github.com/vuejs/eslint-config-airbnb/issues/58"
"eslint": "Cannot migrate to v9 `@typescript-eslint/eslint-plugin` (≤ v7), `@typescript-eslint/parser` (≤ v7), `@vue/eslint-config-airbnb-with-typescript@` (≤ v8) requires `eslint` ≤ v8, see https://github.com/vuejs/eslint-config-airbnb/issues/65, https://github.com/typescript-eslint/typescript-eslint/issues/8211"
}, },
"homepage": "https://privacy.sexy", "homepage": "https://privacy.sexy",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/undergroundwires/privacy.sexy.git" "url": "https://github.com/undergroundwires/privacy.sexy.git"
},
"optionalDependencies": {
"dmg-license": "^1.0.11"
},
"//optionalDependencies": {
"dmg-license": "Required by `electron-builder` for DMG builds on macOS, https://github.com/electron-userland/electron-builder/issues/6489, https://github.com/electron-userland/electron-builder/issues/6520"
} }
} }

74
scripts/configure-vscode.sh Executable file
View File

@@ -0,0 +1,74 @@
#!/usr/bin/env bash
# This script ensures that the '.vscode/settings.json' file exists and is configured correctly for ESLint validation on Vue and JavaScript files.
# See https://web.archive.org/web/20230801024405/https://eslint.vuejs.org/user-guide/#visual-studio-code
declare -r SETTINGS_FILE='.vscode/settings.json'
declare -ra CONFIG_KEYS=('vue' 'javascript' 'typescript')
declare -r TEMP_FILE="tmp.$$.json"
main() {
ensure_vscode_directory_exists
create_or_update_settings
}
ensure_vscode_directory_exists() {
local dir_name
dir_name=$(dirname "${SETTINGS_FILE}")
if [[ ! -d ${dir_name} ]]; then
mkdir -p "${dir_name}"
echo "🎉 Created directory: ${dir_name}"
fi
}
create_or_update_settings() {
if [[ ! -f ${SETTINGS_FILE} ]]; then
create_default_settings
else
add_or_update_eslint_validate
fi
}
create_default_settings() {
local default_validate
default_validate=$(printf '%s' "${CONFIG_KEYS[*]}" | jq -R -s -c -M 'split(" ")')
echo "{ \"eslint.validate\": ${default_validate} }" | jq '.' > "${SETTINGS_FILE}"
echo "🎉 Created default ${SETTINGS_FILE}"
}
add_or_update_eslint_validate() {
if ! jq -e '.["eslint.validate"]' "${SETTINGS_FILE}" >/dev/null; then
add_default_eslint_validate
else
update_eslint_validate
fi
}
add_default_eslint_validate() {
jq --argjson keys "$(printf '%s' "${CONFIG_KEYS[*]}" \
| jq -R -s -c 'split(" ")')" '. += {"eslint.validate": $keys}' "${SETTINGS_FILE}" > "${TEMP_FILE}"
replace_and_confirm
echo "🎉 Added default 'eslint.validate' to ${SETTINGS_FILE}"
}
update_eslint_validate() {
local existing_keys
existing_keys=$(jq '.["eslint.validate"]' "${SETTINGS_FILE}")
for key in "${CONFIG_KEYS[@]}"; do
if ! echo "${existing_keys}" | jq 'index("'"${key}"'")' >/dev/null; then
jq '.["eslint.validate"] += ["'"${key}"'"]' "${SETTINGS_FILE}" > "${TEMP_FILE}"
mv "${TEMP_FILE}" "${SETTINGS_FILE}"
echo "🎉 Updated 'eslint.validate' in ${SETTINGS_FILE} for ${key}"
else
echo "⏩️ No updated needed for ${key} ${SETTINGS_FILE}."
fi
done
}
replace_and_confirm() {
if mv "${TEMP_FILE}" "${SETTINGS_FILE}"; then
echo "🎉 Updated ${SETTINGS_FILE}"
fi
}
main

View File

@@ -1,190 +0,0 @@
"""
Description:
This script configures project-level VSCode settings in '.vscode/settings.json' for
development and installs recommended extensions from '.vscode/extensions.json'.
Usage:
python3 ./scripts/configure_vscode.py
"""
# pylint: disable=missing-function-docstring
import os
import json
from pathlib import Path
import subprocess
import sys
import re
from typing import Any, Optional
from shutil import which
VSCODE_SETTINGS_JSON_FILE: str = '.vscode/settings.json'
VSCODE_EXTENSIONS_JSON_FILE: str = '.vscode/extensions.json'
def main() -> None:
ensure_vscode_directory_exists()
ensure_setting_file_exists()
add_or_update_settings()
install_recommended_extensions()
def ensure_vscode_directory_exists() -> None:
vscode_directory_path = os.path.dirname(VSCODE_SETTINGS_JSON_FILE)
try:
os.makedirs(vscode_directory_path, exist_ok=True)
print_success(f"Created or verified directory: {vscode_directory_path}")
except OSError as error:
print_error(f"Error handling directory {vscode_directory_path}: {error}")
def ensure_setting_file_exists() -> None:
try:
if os.path.isfile(VSCODE_SETTINGS_JSON_FILE):
print_success(f"VSCode settings file exists: {VSCODE_SETTINGS_JSON_FILE}")
return
with open(VSCODE_SETTINGS_JSON_FILE, 'w', encoding='utf-8') as file:
json.dump({}, file, indent=4)
print_success(f"Created empty {VSCODE_SETTINGS_JSON_FILE}")
except IOError as error:
print_error(f"Error creating file {VSCODE_SETTINGS_JSON_FILE}: {error}")
print_success(f"Created empty {VSCODE_SETTINGS_JSON_FILE}")
def add_or_update_settings() -> None:
configure_setting_key('eslint.validate', ['vue', 'javascript', 'typescript'])
# Set ESLint validation for specific file types.
# Details: # pylint: disable-next=line-too-long
# - https://web.archive.org/web/20230801024405/https://eslint.vuejs.org/user-guide/#visual-studio-code
configure_setting_key('terminal.integrated.env.linux', {"GTK_PATH": ""})
# Unset GTK_PATH on Linux for Electron development in sandboxed environments
# like Snap or Flatpak VSCode installations, enabling script execution.
# Details: # pylint: disable-next=line-too-long
# - https://archive.ph/2024.01.06-003914/https://github.com/microsoft/vscode/issues/179274, https://web.archive.org/web/20240106003915/https://github.com/microsoft/vscode/issues/179274
# Disable telemetry
configure_setting_key('redhat.telemetry.enabled', False)
configure_setting_key('gitlens.telemetry.enabled', False)
def configure_setting_key(configuration_key: str, desired_value: Any) -> None:
try:
with open(VSCODE_SETTINGS_JSON_FILE, 'r+', encoding='utf-8') as file:
settings: dict = json.load(file)
if configuration_key in settings:
actual_value = settings[configuration_key]
if actual_value == desired_value:
print_skip(f"Already configured as desired: \"{configuration_key}\"")
return
settings[configuration_key] = desired_value
file.seek(0)
json.dump(settings, file, indent=4)
file.truncate()
print_success(f"Added or updated configuration: {configuration_key}")
except json.JSONDecodeError:
print_error(f"Failed to update JSON for key {configuration_key}.")
def install_recommended_extensions() -> None:
if not os.path.isfile(VSCODE_EXTENSIONS_JSON_FILE):
print_error(
f"The extensions.json file does not exist in the path: {VSCODE_EXTENSIONS_JSON_FILE}."
)
return
with open(VSCODE_EXTENSIONS_JSON_FILE, 'r', encoding='utf-8') as file:
json_content: str = remove_json_comments(file.read())
try:
data: dict = json.loads(json_content)
extensions: list[str] = data.get("recommendations", [])
if not extensions:
print_skip(f"No recommendations found in the {VSCODE_EXTENSIONS_JSON_FILE} file.")
return
vscode_cli_path = locate_vscode_cli()
if vscode_cli_path is None:
print_error('Visual Studio Code CLI (`code`) tool not found.')
return
install_vscode_extensions(vscode_cli_path, extensions)
except json.JSONDecodeError:
print_error(f"Invalid JSON in {VSCODE_EXTENSIONS_JSON_FILE}")
def locate_vscode_cli() -> Optional[str]:
vscode_alias = which('code') # More reliable than using `code`, especially on Windows.
if vscode_alias:
return vscode_alias
potential_vscode_cli_paths = [
# VS Code on macOS may not register 'code' command in PATH
'/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code'
]
for vscode_cli_candidate_path in potential_vscode_cli_paths:
if Path(vscode_cli_candidate_path).is_file():
return vscode_cli_candidate_path
return None
def remove_json_comments(json_like: str) -> str:
pattern: str = r'(?:"(?:\\.|[^"\\])*"|/\*[\s\S]*?\*/|//.*)|([^:]//.*$)'
return re.sub(
pattern,
lambda m: '' if m.group(1) else m.group(0), json_like, flags=re.MULTILINE,
)
def install_vscode_extensions(vscode_cli_path: str, extensions: list[str]) -> None:
successful_installations = 0
for ext in extensions:
try:
result = subprocess.run(
[vscode_cli_path, "--install-extension", ext],
check=True,
capture_output=True,
text=True,
)
if "already installed" in result.stdout:
print_skip(f"Created or verified directory: {ext}")
else:
print_success(f"Installed extension: {ext}")
successful_installations += 1
print_subprocess_output(result)
except subprocess.CalledProcessError as e:
print_subprocess_output(e)
print_error(f"Failed to install extension: {ext}")
except FileNotFoundError:
print_error(' '.join([
f"Visual Studio Code CLI tool not found: {vscode_cli_path}."
f"Could not install extension: {ext}",
]))
except Exception as e: # pylint: disable=broad-except
print_error(' '.join([
f"Failed to install extension '{ext}'.",
f"Attempted using Visual Studio Code CLI at: '{vscode_cli_path}'.",
f"Encountered error: {e}",
]))
total_extensions = len(extensions)
print_installation_results(successful_installations, total_extensions)
def print_subprocess_output(result: subprocess.CompletedProcess[str]) -> None:
output = '\n'.join([text.strip() for text in [result.stdout, result.stderr] if text])
if not output:
return
formatted_output = '\t' + output.strip().replace('\n', '\n\t')
print(formatted_output)
def print_installation_results(successful_installations: int, total_extensions: int) -> None:
if successful_installations == total_extensions:
print_success(
f"Successfully installed or verified all {total_extensions} recommended extensions."
)
elif successful_installations > 0:
print_warning(
f"Partially successful: Installed or verified {successful_installations} "
f"out of {total_extensions} recommended extensions."
)
else:
print_error("Failed to install any of the recommended extensions.")
def print_error(message: str) -> None:
print(f"[ERROR] {message}", file=sys.stderr)
def print_success(message: str) -> None:
print(f"[SUCCESS] {message}")
def print_skip(message: str) -> None:
print(f"[SKIPPED] {message}")
def print_warning(message: str) -> None:
print(f"[WARNING] {message}", file=sys.stderr)
if __name__ == "__main__":
main()

View File

@@ -1,120 +1,84 @@
/** #!/usr/bin/env bash
* Description: import { resolve, join } from 'path';
* This script updates the logo images across the project based on the primary import { rm, mkdtemp, stat } from 'fs/promises';
* logo file ('img/logo.svg' file). import { spawn } from 'child_process';
* import { URL, fileURLToPath } from 'url';
* It handles the creation and update of various icon sizes for different purposes,
* including desktop launcher icons, tray icons, and web favicons from a single source
* SVG logo file.
*
* Usage:
* node ./scripts/logo-update.js
*
* Notes:
* ImageMagick must be installed and accessible in the system's PATH
*/
import { resolve, join, dirname } from 'node:path'; class Paths {
import { stat } from 'node:fs/promises'; constructor(selfDirectory) {
import { spawn } from 'node:child_process'; const projectRoot = resolve(selfDirectory, '../');
import { URL, fileURLToPath } from 'node:url';
import electronBuilderConfig from '../electron-builder.cjs';
class ImageAssetPaths {
constructor(currentScriptDirectory) {
const projectRoot = resolve(currentScriptDirectory, '../');
this.sourceImage = join(projectRoot, 'img/logo.svg'); this.sourceImage = join(projectRoot, 'img/logo.svg');
this.publicDirectory = join(projectRoot, 'src/presentation/public'); this.publicDirectory = join(projectRoot, 'src/presentation/public');
this.electronBuildResourcesDirectory = electronBuilderConfig.directories.buildResources; this.electronBuildDirectory = join(projectRoot, 'build');
}
get electronTrayIconFile() {
return join(this.publicDirectory, 'icon.png');
}
get webFaviconFile() {
return join(this.publicDirectory, 'favicon.ico');
} }
toString() { toString() {
return `Source image: ${this.sourceImage}` return `Source image: ${this.sourceImage}\n`
+ `\nPublic directory: ${this.publicDirectory}` + `Public directory: ${this.publicDirectory}\n`
+ `\n\t Electron tray icon file: ${this.electronTrayIconFile}` + `Electron build directory: ${this.electronBuildDirectory}`;
+ `\n\t Web favicon file: ${this.webFaviconFile}`
+ `\nElectron build directory: ${this.electronBuildResourcesDirectory}`;
} }
} }
async function main() { async function main() {
const paths = new ImageAssetPaths(getCurrentScriptDirectory()); const paths = new Paths(getCurrentScriptDirectory());
console.log(`Paths:\n\t${paths.toString().replaceAll('\n', '\n\t')}`); console.log(`Paths:\n\t${paths.toString().replaceAll('\n', '\n\t')}`);
const convertCommand = await findAvailableImageMagickCommand(); await updateDesktopLauncherAndTrayIcon(paths.sourceImage, paths.publicDirectory);
await generateDesktopAndTrayIcons( await updateWebFavicon(paths.sourceImage, paths.publicDirectory);
paths.sourceImage, await updateDesktopIcons(paths.sourceImage, paths.electronBuildDirectory);
paths.electronTrayIconFile,
convertCommand,
);
await generateWebFavicon(
paths.sourceImage,
paths.webFaviconFile,
convertCommand,
);
await generateDesktopIcons(
paths.sourceImage,
paths.electronBuildResourcesDirectory,
convertCommand,
);
console.log('🎉 (Re)created icons successfully.'); console.log('🎉 (Re)created icons successfully.');
} }
async function generateDesktopAndTrayIcons(sourceImage, targetFile, convertCommand) { async function updateDesktopLauncherAndTrayIcon(sourceImage, publicFolder) {
// Reference: https://web.archive.org/web/20240502124306/https://www.electronjs.org/docs/latest/api/tray
console.log(`Updating desktop launcher and tray icon at ${targetFile}.`);
await ensureFileExists(sourceImage); await ensureFileExists(sourceImage);
await ensureParentFolderExists(targetFile); await ensureFolderExists(publicFolder);
await convertFromSvgToPng( const electronTrayIconFile = join(publicFolder, 'icon.png');
convertCommand, console.log(`Updating desktop launcher and tray icon at ${electronTrayIconFile}.`);
await runCommand(
'npx',
'svgexport',
sourceImage, sourceImage,
targetFile, electronTrayIconFile,
'512x512',
); );
} }
async function generateWebFavicon(sourceImage, faviconFilePath, convertCommand) { async function updateWebFavicon(sourceImage, faviconFolder) {
console.log(`Updating favicon at ${faviconFilePath}.`); console.log('Updating favicon');
await ensureFileExists(sourceImage); await ensureFileExists(sourceImage);
await ensureParentFolderExists(faviconFilePath); await ensureFolderExists(faviconFolder);
await convertFromSvgToIco( await runCommand(
convertCommand, 'npx',
sourceImage, 'icon-gen',
faviconFilePath, `--input ${sourceImage}`,
[16, 24, 32, 48, 64, 128, 256], `--output ${faviconFolder}`,
'--ico',
'--ico-name \'favicon\'',
'--report',
); );
} }
async function generateDesktopIcons(sourceImage, electronBuildResourcesDirectory, convertCommand) { async function updateDesktopIcons(sourceImage, electronIconsDir) {
console.log(`Creating Electron icon files to ${electronBuildResourcesDirectory}.`);
// Reference: https://web.archive.org/web/20240501103645/https://www.electron.build/icons.html
await ensureFolderExists(electronBuildResourcesDirectory);
await ensureFileExists(sourceImage); await ensureFileExists(sourceImage);
const electronMainIconFile = join(electronBuildResourcesDirectory, 'icon.png'); await ensureFolderExists(electronIconsDir);
await convertFromSvgToPng( const temporaryDir = await mkdtemp('icon-');
convertCommand, const temporaryPngFile = join(temporaryDir, 'icon.png');
console.log(`Converting from SVG (${sourceImage}) to PNG: ${temporaryPngFile}`); // required by `icon-builder`
await runCommand(
'npx',
'svgexport',
sourceImage, sourceImage,
electronMainIconFile, temporaryPngFile,
'1024x1024', // Should be at least 512x512 '1024:1024',
); );
// Relying on `electron-builder`s conversion from png to ico results in pixelated look on Windows console.log(`Creating electron icons to ${electronIconsDir}.`);
// 10 and 11 according to tests, see: await runCommand(
// - https://web.archive.org/web/20240502114650/https://github.com/electron-userland/electron-builder/issues/7328 'npx',
// - https://web.archive.org/web/20240502115448/https://github.com/electron-userland/electron-builder/issues/3867 'electron-icon-builder',
const electronWindowsIconFile = join(electronBuildResourcesDirectory, 'icon.ico'); `--input="${temporaryPngFile}"`,
await convertFromSvgToIco( `--output="${electronIconsDir}"`,
convertCommand, '--flatten',
sourceImage,
electronWindowsIconFile,
[16, 24, 32, 48, 64, 128, 256],
); );
console.log('Cleaning up temporary directory.');
await rm(temporaryDir, { recursive: true, force: true });
} }
async function ensureFileExists(filePath) { async function ensureFileExists(filePath) {
@@ -125,60 +89,12 @@ async function ensureFileExists(filePath) {
} }
async function ensureFolderExists(folderPath) { async function ensureFolderExists(folderPath) {
if (!folderPath) {
throw new Error('Path is missing');
}
const path = await stat(folderPath); const path = await stat(folderPath);
if (!path.isDirectory()) { if (!path.isDirectory()) {
throw new Error(`Not a directory: ${folderPath}`); throw new Error(`Not a directory: ${folderPath}`);
} }
} }
function ensureParentFolderExists(filePath) {
return ensureFolderExists(dirname(filePath));
}
const BaseImageMagickConvertArguments = Object.freeze([
'-background none', // Transparent, so they do not get filled with white.
'-strip', // Strip metadata.
'-gravity Center', // Center the image when there's empty space
]);
async function convertFromSvgToIco(
convertCommand,
inputFile,
outputFile,
sizes,
) {
await runCommand(
convertCommand,
...BaseImageMagickConvertArguments,
`-density ${Math.max(...sizes).toString()}`, // High enough for sharpness
`-define icon:auto-resize=${sizes.map((s) => s.toString()).join(',')}`, // Automatically store multiple sizes in an ico image
'-compress None',
inputFile,
outputFile,
);
}
async function convertFromSvgToPng(
convertCommand,
inputFile,
outputFile,
size = undefined,
) {
await runCommand(
convertCommand,
...BaseImageMagickConvertArguments,
...(size === undefined ? [] : [
`-resize ${size}`,
`-density ${size}`, // High enough for sharpness
]),
inputFile,
outputFile,
);
}
async function runCommand(...args) { async function runCommand(...args) {
const command = args.join(' '); const command = args.join(' ');
console.log(`Running command: ${command}`); console.log(`Running command: ${command}`);
@@ -208,27 +124,4 @@ function getCurrentScriptDirectory() {
return fileURLToPath(new URL('.', import.meta.url)); return fileURLToPath(new URL('.', import.meta.url));
} }
async function findAvailableImageMagickCommand() {
// Reference: https://web.archive.org/web/20240502120041/https://imagemagick.org/script/convert.php
const potentialBaseCommands = [
'convert', // Legacy command, usually available on Linux/macOS installations
'magick convert', // Newer command, available on Windows installations
];
for (const baseCommand of potentialBaseCommands) {
const testCommand = `${baseCommand} -version`;
try {
await runCommand(testCommand); // eslint-disable-line no-await-in-loop
console.log(`Confirmed: ImageMagick command '${baseCommand}' is available and operational.`);
return baseCommand;
} catch (err) {
console.log(`Error: The command '${baseCommand}' is not found or failed to execute. Detailed error: ${err.message}"`);
}
}
throw new Error([
'Unable to locate any operational ImageMagick command.',
`Attempted commands were: ${potentialBaseCommands.join(', ')}.`,
'Please ensure ImageMagick is correctly installed and accessible.',
].join('\n'));
}
await main(); await main();

View File

@@ -35,10 +35,10 @@ Note:
Example: npm run install-deps -- --fresh --non-deterministic Example: npm run install-deps -- --fresh --non-deterministic
*/ */
import { exec } from 'node:child_process'; import { exec } from 'child_process';
import { resolve } from 'node:path'; import { resolve } from 'path';
import { access, rm, unlink } from 'node:fs/promises'; import { access, rm, unlink } from 'fs/promises';
import { constants } from 'node:fs'; import { constants } from 'fs';
const MAX_RETRIES = 5; const MAX_RETRIES = 5;
const RETRY_DELAY_IN_MS = 5 /* seconds */ * 1000; const RETRY_DELAY_IN_MS = 5 /* seconds */ * 1000;

View File

@@ -12,8 +12,8 @@
* --web Path for the web application * --web Path for the web application
*/ */
import { resolve } from 'node:path'; import { resolve } from 'path';
import { readFile } from 'node:fs/promises'; import { readFile } from 'fs/promises';
const DIST_DIRS_JSON_FILE_PATH = resolve(process.cwd(), 'dist-dirs.json'); // cannot statically import because ESLint does not support it https://github.com/eslint/eslint/discussions/15305 const DIST_DIRS_JSON_FILE_PATH = resolve(process.cwd(), 'dist-dirs.json'); // cannot statically import because ESLint does not support it https://github.com/eslint/eslint/discussions/15305
const CLI_ARGUMENTS = process.argv.slice(2); const CLI_ARGUMENTS = process.argv.slice(2);

View File

@@ -1,51 +0,0 @@
# validate-collections-yaml
This script validates YAML collection files against a predefined schema to ensure their integrity.
## Prerequisites
- Python 3.x installed on your system.
## Running in a Virtual Environment (Recommended)
Using a virtual environment isolates dependencies and prevents conflicts.
1. **Create a virtual environment:**
```bash
python3 -m venv ./scripts/validate-collections-yaml/.venv
```
2. **Activate the virtual environment:**
```bash
source ./scripts/validate-collections-yaml/.venv/bin/activate
```
3. **Install dependencies:**
```bash
python3 -m pip install -r ./scripts/validate-collections-yaml/requirements.txt
```
4. **Run the script:**
```bash
python3 ./scripts/validate-collections-yaml
```
## Running Globally
Running the script globally is less recommended due to potential dependency conflicts.
1. **Install dependencies:**
```bash
python3 -m pip install -r ./scripts/validate-collections-yaml/requirements.txt
```
2. **Run the script:**
```bash
python3 ./scripts/validate-collections-yaml
```

View File

@@ -1,62 +0,0 @@
"""
Description:
This script validates collection YAML files against the expected schema.
Usage:
python3 ./scripts/validate-collections-yaml
Notes:
This script requires the `jsonschema` and `pyyaml` packages (see requirements.txt).
"""
# pylint: disable=missing-function-docstring
from os import path
import sys
from glob import glob
from typing import List
from jsonschema import exceptions, validate # pylint: disable=import-error
import yaml # pylint: disable=import-error
SCHEMA_FILE_PATH = './src/application/collections/.schema.yaml'
COLLECTIONS_GLOB_PATTERN = './src/application/collections/*.yaml'
def main() -> None:
schema_yaml = read_file(SCHEMA_FILE_PATH)
schema_json = convert_yaml_to_json(schema_yaml)
collection_file_paths = find_collection_files(COLLECTIONS_GLOB_PATTERN)
print(f'Found {len(collection_file_paths)} YAML files to validate.')
total_invalid_files = 0
for collection_file_path in collection_file_paths:
file_name = path.basename(collection_file_path)
print(f'Validating {file_name}...')
collection_yaml = read_file(collection_file_path)
collection_json = convert_yaml_to_json(collection_yaml)
try:
validate(instance=collection_json, schema=schema_json)
print(f'Success: {file_name} is valid.')
except exceptions.ValidationError as err:
print(f'Error: Validation failed for {file_name}.', file=sys.stderr)
print(str(err), file=sys.stderr)
total_invalid_files += 1
if total_invalid_files > 0:
print(f'Validation complete with {total_invalid_files} invalid files.', file=sys.stderr)
sys.exit(1)
else:
print('Validation complete. All files are valid.')
sys.exit(0)
def read_file(file_path: str) -> str:
with open(file_path, 'r', encoding='utf-8') as file:
return file.read()
def find_collection_files(glob_pattern: str) -> List[str]:
files = glob(glob_pattern)
filtered_files = [f for f in files if not path.basename(f).startswith('.')]
return filtered_files
def convert_yaml_to_json(yaml_content: str) -> dict:
return yaml.safe_load(yaml_content)
if __name__ == '__main__':
main()

View File

@@ -1,6 +0,0 @@
attrs==23.2.0
jsonschema==4.22.0
jsonschema-specifications==2023.12.1
PyYAML==6.0.1
referencing==0.35.1
rpds-py==0.18.1

View File

@@ -13,9 +13,9 @@
* --web Verify artifacts for the web application. * --web Verify artifacts for the web application.
*/ */
import { access, readdir } from 'node:fs/promises'; import { access, readdir } from 'fs/promises';
import { exec } from 'node:child_process'; import { exec } from 'child_process';
import { resolve } from 'node:path'; import { resolve } from 'path';
const PROCESS_ARGUMENTS = process.argv.slice(2); const PROCESS_ARGUMENTS = process.argv.slice(2);
const PRINT_DIST_DIR_SCRIPT_BASE_COMMAND = 'node scripts/print-dist-dir'; const PRINT_DIST_DIR_SCRIPT_BASE_COMMAND = 'node scripts/print-dist-dir';
@@ -44,8 +44,8 @@ function getBuildVerificationConfigs() {
'--electron-unbundled': { '--electron-unbundled': {
printDistDirScriptArgument: '--electron-unbundled', printDistDirScriptArgument: '--electron-unbundled',
filePatterns: [ filePatterns: [
/main[/\\]index\.(cjs|mjs|js)/, /main[/\\]index\.cjs/,
/preload[/\\]index\.(cjs|mjs|js)/, /preload[/\\]index\.cjs/,
/renderer[/\\]index\.htm(l)?/, /renderer[/\\]index\.htm(l)?/,
], ],
}, },
@@ -91,7 +91,7 @@ async function verifyFilesExist(directoryPath, filePatterns) {
if (!match) { if (!match) {
die( die(
`No file matches the pattern ${pattern.source} in directory \`${directoryPath}\``, `No file matches the pattern ${pattern.source} in directory \`${directoryPath}\``,
`\nFiles in directory:\n${files.map((file) => `- ${file}`).join('\n')}`, `\nFiles in directory:\n${files.map((file) => `\t- ${file}`).join('\n')}`,
); );
} }
} }

View File

@@ -1,87 +1,62 @@
#!/usr/bin/env node
/** /**
* Description: * Description:
* This script checks if a server, provided as a CLI argument, is up * This script checks if a server, provided as a CLI argument, is up
* and returns an HTTP 200 status code. * and returns an HTTP 200 status code.
* It is designed to provide easy verification of server availability * It is designed to provide easy verification of server availability
* and will retry a specified number of times. * and will retry a specified number of times.
* *
* Usage: * Usage:
* node ./scripts/verify-web-server-status.js --url [URL] [--max-retries NUMBER] * node ./scripts/verify-web-server-status.js --url [URL]
* *
* Options: * Options:
* --url URL of the server to check * --url URL of the server to check
* --max-retries Maximum number of retry attempts (default: 30)
*/ */
const DEFAULT_MAX_RETRIES = 30; import { get } from 'http';
const RETRY_DELAY_IN_SECONDS = 3;
const PARAMETER_NAME_URL = '--url';
const PARAMETER_NAME_MAX_RETRIES = '--max-retries';
async function checkServer(currentRetryCount = 1) { const MAX_RETRIES = 30;
const serverUrl = readRequiredParameterValue(PARAMETER_NAME_URL); const RETRY_DELAY_IN_SECONDS = 3;
const maxRetries = parseNumber( const URL_PARAMETER_NAME = '--url';
readOptionalParameterValue(PARAMETER_NAME_MAX_RETRIES, DEFAULT_MAX_RETRIES),
); function checkServer(currentRetryCount = 1) {
console.log(`🌐 Requesting ${serverUrl}...`); const serverUrl = getServerUrl();
try { console.log(`Requesting ${serverUrl}...`);
const response = await fetch(serverUrl); get(serverUrl, (res) => {
if (response.status === 200) { if (res.statusCode === 200) {
console.log('🎊 Success: The server is up and returned HTTP 200.'); console.log('🎊 Success: The server is up and returned HTTP 200.');
process.exit(0); process.exit(0);
} else { } else {
exitWithError(`Server returned unexpected HTTP status code ${response.statusCode}.`); console.log(`Server returned HTTP status code ${res.statusCode}.`);
retry(currentRetryCount);
} }
} catch (error) { }).on('error', (err) => {
console.error('Error making the request:', error); console.error('Error making the request:', err);
scheduleNextRetry(maxRetries, currentRetryCount); retry(currentRetryCount);
} });
} }
function scheduleNextRetry(maxRetries, currentRetryCount) { function retry(currentRetryCount) {
console.log(`Attempt ${currentRetryCount}/${maxRetries}:`); console.log(`Attempt ${currentRetryCount}/${MAX_RETRIES}:`);
console.log(`Retrying in ${RETRY_DELAY_IN_SECONDS} seconds.`); console.log(`Retrying in ${RETRY_DELAY_IN_SECONDS} seconds.`);
const remainingTime = (maxRetries - currentRetryCount) * RETRY_DELAY_IN_SECONDS; const remainingTime = (MAX_RETRIES - currentRetryCount) * RETRY_DELAY_IN_SECONDS;
console.log(`Time remaining before timeout: ${remainingTime}s`); console.log(`Time remaining before timeout: ${remainingTime}s`);
if (currentRetryCount < maxRetries) { if (currentRetryCount < MAX_RETRIES) {
setTimeout(() => checkServer(currentRetryCount + 1), RETRY_DELAY_IN_SECONDS * 1000); setTimeout(() => checkServer(currentRetryCount + 1), RETRY_DELAY_IN_SECONDS * 1000);
} else { } else {
exitWithError('The server at did not return HTTP 200 within the allocated time.'); console.log('Failure: The server at did not return HTTP 200 within the allocated time. Exiting.');
process.exit(1);
} }
} }
function readRequiredParameterValue(parameterName) { function getServerUrl() {
const parameterValue = readOptionalParameterValue(parameterName); const urlIndex = process.argv.indexOf(URL_PARAMETER_NAME);
if (parameterValue === undefined) { if (urlIndex === -1 || urlIndex === process.argv.length - 1) {
exitWithError(`Parameter "${parameterName}" is required but not provided.`); console.error(`Parameter "${URL_PARAMETER_NAME}" is not provided.`);
process.exit(1);
} }
return parameterValue; return process.argv[urlIndex + 1];
} }
function readOptionalParameterValue(parameterName, defaultValue) { checkServer();
const index = process.argv.indexOf(parameterName);
if (index === -1 || index === process.argv.length - 1) {
return defaultValue;
}
return process.argv[index + 1];
}
function parseNumber(numberLike) {
const number = parseInt(numberLike, 10);
if (Number.isNaN(number)) {
exitWithError(`Invalid number: ${numberLike}`);
}
return number;
}
function exitWithError(message) {
console.error(`Failure: ${message}`);
console.log('Exiting');
process.exit(1);
}
await checkServer();

View File

@@ -14,35 +14,3 @@ export type ConstructorArguments<T> =
export type FunctionKeys<T> = { export type FunctionKeys<T> = {
[K in keyof T]: T[K] extends (...args: unknown[]) => unknown ? K : never; [K in keyof T]: T[K] extends (...args: unknown[]) => unknown ? K : never;
}[keyof T]; }[keyof T];
export function isString(value: unknown): value is string {
return typeof value === 'string';
}
export function isNumber(value: unknown): value is number {
return typeof value === 'number';
}
export function isBoolean(value: unknown): value is boolean {
return typeof value === 'boolean';
}
export function isFunction(value: unknown): value is (...args: unknown[]) => unknown {
return typeof value === 'function';
}
export function isArray(value: unknown): value is Array<unknown> {
return Array.isArray(value);
}
export function isPlainObject(
variable: unknown,
): variable is object & Record<string, unknown> {
return Boolean(variable) // the data type of null is an object
&& typeof variable === 'object'
&& !Array.isArray(variable);
}
export function isNullOrUndefined(value: unknown): value is (null | undefined) {
return typeof value === 'undefined' || value === null;
}

View File

@@ -1,7 +1,7 @@
import type { IApplication } from '@/domain/IApplication'; import { IApplication } from '@/domain/IApplication';
import { AsyncLazy } from '@/infrastructure/Threading/AsyncLazy'; import { AsyncLazy } from '@/infrastructure/Threading/AsyncLazy';
import { IApplicationFactory } from './IApplicationFactory';
import { parseApplication } from './Parser/ApplicationParser'; import { parseApplication } from './Parser/ApplicationParser';
import type { IApplicationFactory } from './IApplicationFactory';
export type ApplicationGetterType = () => IApplication; export type ApplicationGetterType = () => IApplication;
const ApplicationGetter: ApplicationGetterType = parseApplication; const ApplicationGetter: ApplicationGetterType = parseApplication;
@@ -12,6 +12,9 @@ export class ApplicationFactory implements IApplicationFactory {
private readonly getter: AsyncLazy<IApplication>; private readonly getter: AsyncLazy<IApplication>;
protected constructor(costlyGetter: ApplicationGetterType) { protected constructor(costlyGetter: ApplicationGetterType) {
if (!costlyGetter) {
throw new Error('missing getter');
}
this.getter = new AsyncLazy<IApplication>(() => Promise.resolve(costlyGetter())); this.getter = new AsyncLazy<IApplication>(() => Promise.resolve(costlyGetter()));
} }

View File

@@ -1,38 +0,0 @@
export interface CodeRunner {
runCode(
code: string,
fileExtension: string,
): Promise<CodeRunOutcome>;
}
export type CodeRunOutcome = SuccessfulCodeRun | FailedCodeRun;
export type CodeRunErrorType =
| 'FileWriteError'
| 'FileReadbackVerificationError'
| 'FilePathGenerationError'
| 'UnsupportedPlatform'
| 'DirectoryCreationError'
| 'FilePermissionChangeError'
| 'FileExecutionError'
| 'ExternalProcessTermination';
interface CodeRunStatus {
readonly success: boolean;
readonly error?: CodeRunError;
}
interface SuccessfulCodeRun extends CodeRunStatus {
readonly success: true;
readonly error?: undefined;
}
export interface FailedCodeRun extends CodeRunStatus {
readonly success: false;
readonly error: CodeRunError;
}
export interface CodeRunError {
readonly type: CodeRunErrorType;
readonly message: string;
}

View File

@@ -1 +0,0 @@
export const ScriptFilename = 'privacy-script' as const;

View File

@@ -1,5 +1,7 @@
// Compares to Array<T> objects for equality, ignoring order // Compares to Array<T> objects for equality, ignoring order
export function scrambledEqual<T>(array1: readonly T[], array2: readonly T[]) { export function scrambledEqual<T>(array1: readonly T[], array2: readonly T[]) {
if (!array1) { throw new Error('missing first array'); }
if (!array2) { throw new Error('missing second array'); }
const sortedArray1 = sort(array1); const sortedArray1 = sort(array1);
const sortedArray2 = sort(array2); const sortedArray2 = sort(array2);
return sequenceEqual(sortedArray1, sortedArray2); return sequenceEqual(sortedArray1, sortedArray2);
@@ -10,6 +12,8 @@ export function scrambledEqual<T>(array1: readonly T[], array2: readonly T[]) {
// Compares to Array<T> objects for equality in same order // Compares to Array<T> objects for equality in same order
export function sequenceEqual<T>(array1: readonly T[], array2: readonly T[]) { export function sequenceEqual<T>(array1: readonly T[], array2: readonly T[]) {
if (!array1) { throw new Error('missing first array'); }
if (!array2) { throw new Error('missing second array'); }
if (array1.length !== array2.length) { if (array1.length !== array2.length) {
return false; return false;
} }

View File

@@ -1,5 +1,3 @@
import { isFunction, type ConstructorArguments } from '@/TypeHelpers';
/* /*
Provides a unified and resilient way to extend errors across platforms. Provides a unified and resilient way to extend errors across platforms.
@@ -12,8 +10,8 @@ import { isFunction, type ConstructorArguments } from '@/TypeHelpers';
> https://web.archive.org/web/20230810014143/https://github.com/Microsoft/TypeScript-wiki/blob/main/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work > https://web.archive.org/web/20230810014143/https://github.com/Microsoft/TypeScript-wiki/blob/main/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
*/ */
export abstract class CustomError extends Error { export abstract class CustomError extends Error {
constructor(...args: ConstructorArguments<typeof Error>) { constructor(message?: string, options?: ErrorOptions) {
super(...args); super(message, options);
fixPrototype(this, new.target.prototype); fixPrototype(this, new.target.prototype);
ensureStackTrace(this); ensureStackTrace(this);
@@ -22,33 +20,31 @@ export abstract class CustomError extends Error {
} }
} }
interface ErrorPrototypeManipulation { export const Environment = {
getSetPrototypeOf: () => (typeof Object.setPrototypeOf | undefined);
getCaptureStackTrace: () => (typeof Error.captureStackTrace | undefined);
}
export const PlatformErrorPrototypeManipulation: ErrorPrototypeManipulation = {
getSetPrototypeOf: () => Object.setPrototypeOf, getSetPrototypeOf: () => Object.setPrototypeOf,
getCaptureStackTrace: () => Error.captureStackTrace, getCaptureStackTrace: () => Error.captureStackTrace,
}; };
function fixPrototype(target: Error, prototype: CustomError) { function fixPrototype(target: Error, prototype: CustomError) {
// This is recommended by TypeScript guidelines. // https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget
// Source: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget const setPrototypeOf = Environment.getSetPrototypeOf();
// Snapshots: https://web.archive.org/web/20231111234849/https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget, https://archive.ph/tr7cX#support-for-newtarget if (!functionExists(setPrototypeOf)) {
const setPrototypeOf = PlatformErrorPrototypeManipulation.getSetPrototypeOf();
if (!isFunction(setPrototypeOf)) {
return; return;
} }
setPrototypeOf(target, prototype); setPrototypeOf(target, prototype);
} }
function ensureStackTrace(target: Error) { function ensureStackTrace(target: Error) {
const captureStackTrace = PlatformErrorPrototypeManipulation.getCaptureStackTrace(); const captureStackTrace = Environment.getCaptureStackTrace();
if (!isFunction(captureStackTrace)) { if (!functionExists(captureStackTrace)) {
// captureStackTrace is only available on V8, if it's not available // captureStackTrace is only available on V8, if it's not available
// modern JS engines will usually generate a stack trace on error objects when they're thrown. // modern JS engines will usually generate a stack trace on error objects when they're thrown.
return; return;
} }
captureStackTrace(target, target.constructor); captureStackTrace(target, target.constructor);
} }
function functionExists(func: unknown): boolean {
// Not doing truthy/falsy check i.e. if(func) as most values are truthy in JS for robustness
return typeof func === 'function';
}

View File

@@ -1,17 +1,15 @@
import { isString } from '@/TypeHelpers';
// Because we cannot do "T extends enum" 😞 https://github.com/microsoft/TypeScript/issues/30611 // Because we cannot do "T extends enum" 😞 https://github.com/microsoft/TypeScript/issues/30611
export type EnumType = number | string; export type EnumType = number | string;
export type EnumVariable<T extends EnumType, TEnumValue extends EnumType> export type EnumVariable<T extends EnumType, TEnumValue extends EnumType>
= { [key in T]: TEnumValue }; = { [key in T]: TEnumValue };
export interface EnumParser<TEnum> { export interface IEnumParser<TEnum> {
parseEnum(value: string, propertyName: string): TEnum; parseEnum(value: string, propertyName: string): TEnum;
} }
export function createEnumParser<T extends EnumType, TEnumValue extends EnumType>( export function createEnumParser<T extends EnumType, TEnumValue extends EnumType>(
enumVariable: EnumVariable<T, TEnumValue>, enumVariable: EnumVariable<T, TEnumValue>,
): EnumParser<TEnumValue> { ): IEnumParser<TEnumValue> {
return { return {
parseEnum: (value, propertyName) => parseEnumValue(value, propertyName, enumVariable), parseEnum: (value, propertyName) => parseEnumValue(value, propertyName, enumVariable),
}; };
@@ -25,7 +23,7 @@ function parseEnumValue<T extends EnumType, TEnumValue extends EnumType>(
if (!value) { if (!value) {
throw new Error(`missing ${enumName}`); throw new Error(`missing ${enumName}`);
} }
if (!isString(value)) { if (typeof value !== 'string') {
throw new Error(`unexpected type of ${enumName}: "${typeof value}"`); throw new Error(`unexpected type of ${enumName}: "${typeof value}"`);
} }
const casedValue = getEnumNames(enumVariable) const casedValue = getEnumNames(enumVariable)
@@ -33,31 +31,32 @@ function parseEnumValue<T extends EnumType, TEnumValue extends EnumType>(
if (!casedValue) { if (!casedValue) {
throw new Error(`unknown ${enumName}: "${value}"`); throw new Error(`unknown ${enumName}: "${value}"`);
} }
return enumVariable[casedValue as keyof EnumVariable<T, TEnumValue>]; return enumVariable[casedValue as keyof typeof enumVariable];
} }
export function getEnumNames export function getEnumNames
<T extends EnumType, TEnumValue extends EnumType>( <T extends EnumType, TEnumValue extends EnumType>(
enumVariable: EnumVariable<T, TEnumValue>, enumVariable: EnumVariable<T, TEnumValue>,
): (string & keyof EnumVariable<T, TEnumValue>)[] { ): string[] {
return Object return Object
.values(enumVariable) .values(enumVariable)
.filter(( .filter((enumMember) => typeof enumMember === 'string') as string[];
enumMember,
): enumMember is string & (keyof EnumVariable<T, TEnumValue>) => isString(enumMember));
} }
export function getEnumValues<T extends EnumType, TEnumValue extends EnumType>( export function getEnumValues<T extends EnumType, TEnumValue extends EnumType>(
enumVariable: EnumVariable<T, TEnumValue>, enumVariable: EnumVariable<T, TEnumValue>,
): TEnumValue[] { ): TEnumValue[] {
return getEnumNames(enumVariable) return getEnumNames(enumVariable)
.map((name) => enumVariable[name]) as TEnumValue[]; .map((level) => enumVariable[level]) as TEnumValue[];
} }
export function assertInRange<T extends EnumType, TEnumValue extends EnumType>( export function assertInRange<T extends EnumType, TEnumValue extends EnumType>(
value: TEnumValue, value: TEnumValue,
enumVariable: EnumVariable<T, TEnumValue>, enumVariable: EnumVariable<T, TEnumValue>,
) { ) {
if (value === undefined || value === null) {
throw new Error('absent enum value');
}
if (!(value in enumVariable)) { if (!(value in enumVariable)) {
throw new RangeError(`enum value "${value}" is out of range`); throw new RangeError(`enum value "${value}" is out of range`);
} }

View File

@@ -1,6 +0,0 @@
export interface Logger {
info(...params: unknown[]): void;
warn(...params: unknown[]): void;
error(...params: unknown[]): void;
debug(...params: unknown[]): void;
}

View File

@@ -1,6 +1,6 @@
import { ScriptingLanguage } from '@/domain/ScriptingLanguage'; import { ScriptingLanguage } from '@/domain/ScriptingLanguage';
import { assertInRange } from '@/application/Common/Enum'; import { assertInRange } from '@/application/Common/Enum';
import type { IScriptingLanguageFactory } from './IScriptingLanguageFactory'; import { IScriptingLanguageFactory } from './IScriptingLanguageFactory';
type Getter<T> = () => T; type Getter<T> = () => T;
@@ -9,16 +9,19 @@ export abstract class ScriptingLanguageFactory<T> implements IScriptingLanguageF
public create(language: ScriptingLanguage): T { public create(language: ScriptingLanguage): T {
assertInRange(language, ScriptingLanguage); assertInRange(language, ScriptingLanguage);
const getter = this.getters.get(language); if (!this.getters.has(language)) {
if (!getter) {
throw new RangeError(`unknown language: "${ScriptingLanguage[language]}"`); throw new RangeError(`unknown language: "${ScriptingLanguage[language]}"`);
} }
const getter = this.getters.get(language);
const instance = getter(); const instance = getter();
return instance; return instance;
} }
protected registerGetter(language: ScriptingLanguage, getter: Getter<T>) { protected registerGetter(language: ScriptingLanguage, getter: Getter<T>) {
assertInRange(language, ScriptingLanguage); assertInRange(language, ScriptingLanguage);
if (!getter) {
throw new Error('missing getter');
}
if (this.getters.has(language)) { if (this.getters.has(language)) {
throw new Error(`${ScriptingLanguage[language]} is already registered`); throw new Error(`${ScriptingLanguage[language]} is already registered`);
} }

View File

@@ -1,12 +0,0 @@
/*
Shuffle an array of strings, returning a new array with elements in random order.
Uses the Fisher-Yates (or Durstenfeld) algorithm.
*/
export function shuffle<T>(array: readonly T[]): T[] {
const shuffledArray = [...array];
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffledArray[i], shuffledArray[j]] = [shuffledArray[j], shuffledArray[i]];
}
return shuffledArray;
}

View File

@@ -1,25 +0,0 @@
import { isArray } from '@/TypeHelpers';
export type OptionalString = string | undefined | null;
export function filterEmptyStrings(
texts: readonly OptionalString[],
isArrayType: typeof isArray = isArray,
): string[] {
if (!isArrayType(texts)) {
throw new Error(`Invalid input: Expected an array, but received type ${typeof texts}.`);
}
assertArrayItemsAreStringLike(texts);
return texts
.filter((title): title is string => Boolean(title));
}
function assertArrayItemsAreStringLike(
texts: readonly unknown[],
): asserts texts is readonly OptionalString[] {
const invalidItems = texts.filter((item) => !(typeof item === 'string' || item === undefined || item === null));
if (invalidItems.length > 0) {
const invalidTypes = invalidItems.map((item) => typeof item).join(', ');
throw new Error(`Invalid array items: Expected items as string, undefined, or null. Received invalid types: ${invalidTypes}.`);
}
}

View File

@@ -1,29 +0,0 @@
import { isString } from '@/TypeHelpers';
import { splitTextIntoLines } from './SplitTextIntoLines';
export function indentText(
text: string,
indentLevel = 1,
utilities: TextIndentationUtilities = DefaultUtilities,
): string {
if (!utilities.isStringType(text)) {
throw new Error(`Indentation error: The input must be a string. Received type: ${typeof text}.`);
}
if (indentLevel <= 0) {
throw new Error(`Indentation error: The indent level must be a positive integer. Received: ${indentLevel}.`);
}
const indentation = '\t'.repeat(indentLevel);
return utilities.splitIntoLines(text)
.map((line) => (line ? `${indentation}${line}` : line))
.join('\n');
}
interface TextIndentationUtilities {
readonly splitIntoLines: typeof splitTextIntoLines;
readonly isStringType: typeof isString;
}
const DefaultUtilities: TextIndentationUtilities = {
splitIntoLines: splitTextIntoLines,
isStringType: isString,
};

View File

@@ -1,11 +0,0 @@
import { isString } from '@/TypeHelpers';
export function splitTextIntoLines(
text: string,
isStringType = isString,
): string[] {
if (!isStringType(text)) {
throw new Error(`Line splitting error: Expected a string but received type '${typeof text}'.`);
}
return text.split(/\r\n|\r|\n/);
}

View File

@@ -1,27 +0,0 @@
import { PlatformTimer } from './PlatformTimer';
import type { TimeoutType, Timer } from './Timer';
export function batchedDebounce<T>(
callback: (batches: readonly T[]) => void,
waitInMs: number,
timer: Timer = PlatformTimer,
): (arg: T) => void {
let lastTimeoutId: TimeoutType | undefined;
let batches: Array<T> = [];
return (arg: T) => {
batches.push(arg);
const later = () => {
callback(batches);
batches = [];
lastTimeoutId = undefined;
};
if (lastTimeoutId !== undefined) {
timer.clearTimeout(lastTimeoutId);
}
lastTimeoutId = timer.setTimeout(later, waitInMs);
};
}

View File

@@ -1,7 +0,0 @@
import type { Timer } from './Timer';
export const PlatformTimer: Timer = {
setTimeout: (callback, ms) => setTimeout(callback, ms),
clearTimeout: (timeoutId) => clearTimeout(timeoutId),
dateNow: () => Date.now(),
};

View File

@@ -1,164 +0,0 @@
/* eslint-disable max-classes-per-file */
import { PlatformTimer } from './PlatformTimer';
import type { Timer, TimeoutType } from './Timer';
export type CallbackType = (..._: readonly unknown[]) => void;
export interface ThrottleOptions {
/** Skip the immediate execution of the callback on the first invoke */
readonly excludeLeadingCall: boolean;
readonly timer: Timer;
}
const DefaultOptions: ThrottleOptions = {
excludeLeadingCall: false,
timer: PlatformTimer,
};
export interface ThrottleFunction {
(
callback: CallbackType,
waitInMs: number,
options?: Partial<ThrottleOptions>,
): CallbackType;
}
export const throttle: ThrottleFunction = (
callback: CallbackType,
waitInMs: number,
options: Partial<ThrottleOptions> = DefaultOptions,
): CallbackType => {
const defaultedOptions: ThrottleOptions = {
...DefaultOptions,
...options,
};
const throttler = new Throttler(waitInMs, callback, defaultedOptions);
return (...args: unknown[]) => throttler.invoke(...args);
};
class Throttler {
private lastExecutionTime: number | null = null;
private executionScheduler: DelayedCallbackScheduler;
constructor(
private readonly waitInMs: number,
private readonly callback: CallbackType,
private readonly options: ThrottleOptions,
) {
if (!waitInMs) { throw new Error('missing delay'); }
if (waitInMs < 0) { throw new Error('negative delay'); }
this.executionScheduler = new DelayedCallbackScheduler(options.timer);
}
public invoke(...args: unknown[]): void {
switch (true) {
case this.isLeadingCallWithinThrottlePeriod(): {
if (this.options.excludeLeadingCall) {
this.scheduleNext(args);
return;
}
this.executeNow(args);
return;
}
case this.isAlreadyScheduled(): {
this.updateNextScheduled(args);
return;
}
case !this.isThrottlePeriodPassed(): {
this.scheduleNext(args);
return;
}
default:
throw new Error('Throttle logical error: no conditions for execution or scheduling were met.');
}
}
private isLeadingCallWithinThrottlePeriod(): boolean {
return this.isThrottlePeriodPassed()
&& !this.isAlreadyScheduled();
}
private isThrottlePeriodPassed(): boolean {
if (this.lastExecutionTime === null) {
return true;
}
const timeSinceLastExecution = this.options.timer.dateNow() - this.lastExecutionTime;
const isThrottleTimePassed = timeSinceLastExecution >= this.waitInMs;
return isThrottleTimePassed;
}
private isAlreadyScheduled(): boolean {
return this.executionScheduler.getNext() !== null;
}
private scheduleNext(args: unknown[]): void {
if (this.executionScheduler.getNext()) {
throw new Error('An execution is already scheduled.');
}
this.executionScheduler.resetNext(
() => this.executeNow(args),
this.waitInMs,
);
}
private updateNextScheduled(args: unknown[]): void {
const nextScheduled = this.executionScheduler.getNext();
if (!nextScheduled) {
throw new Error('A non-existent scheduled execution cannot be updated.');
}
const nextDelay = nextScheduled.scheduledTime - this.dateNow();
this.executionScheduler.resetNext(
() => this.executeNow(args),
nextDelay,
);
}
private executeNow(args: unknown[]): void {
this.callback(...args);
this.lastExecutionTime = this.dateNow();
}
private dateNow(): number {
return this.options.timer.dateNow();
}
}
interface ScheduledCallback {
readonly scheduleTimeoutId: TimeoutType;
readonly scheduledTime: number;
}
class DelayedCallbackScheduler {
private scheduledCallback: ScheduledCallback | null = null;
constructor(
private readonly timer: Timer,
) { }
public getNext(): ScheduledCallback | null {
return this.scheduledCallback;
}
public resetNext(
callback: () => void,
delayInMs: number,
) {
this.clear();
this.scheduledCallback = {
scheduledTime: this.timer.dateNow() + delayInMs,
scheduleTimeoutId: this.timer.setTimeout(() => {
this.clear();
callback();
}, delayInMs),
};
}
private clear() {
if (this.scheduledCallback === null) {
return;
}
this.timer.clearTimeout(this.scheduledCallback.scheduleTimeoutId);
this.scheduledCallback = null;
}
}

View File

@@ -1,8 +0,0 @@
// Allows aligning with both NodeJs (NodeJs.Timeout) and Window type (number)
export type TimeoutType = ReturnType<typeof setTimeout>;
export interface Timer {
setTimeout: (callback: () => void, ms: number) => TimeoutType;
clearTimeout: (timeoutId: TimeoutType) => void;
dateNow(): number;
}

Some files were not shown because too many files have changed in this diff Show More