Compare commits

..

2 Commits

Author SHA1 Message Date
undergroundwires
b042b36aea Add expansion/collapse animations for cards
Key changes:

- Add animation for card opening/collapse.

Other supporting changes:

- Remove card expansion panel to its own component for easier
  maintainability and better separation of concerns.
- Use real DOM element instead of &:before pseudo class for showing
  expansion arrow. This increases by maintainability by separating its
  code and concerns.

- TODO: When one card is expanded and others is also expanded then the
  transition sucks.
2024-03-31 20:07:09 +02:00
undergroundwires
be7a886225 Improve URL checks to reduce false-negatives
This commit improves the URL health checking mechanism to reduce false
negatives.

- Treat all 2XX status codes as successful, addressing issues with codes
  like `204`.
- Exclude URLs within Markdown inline code blocks.
- Send the Host header for improved handling of webpages behind proxies.
- Improve formatting and context for output messages.
- Fix the defaulting options for redirects and cookie handling.
- Add URL exclusion support for non-responsive URLs.
- Update the user agent pool to modern browsers and platforms.
- Improve CI/CD workflow to respond to modifications in the
  `test/checks/external-urls` directory, offering immediate feedback on
  potential impacts to the external URL test.
- Add support for randomizing TLS fingerprint to mimic various clients
  better, improving the effectiveness of checks. However, this is not
  fully supported by Node.js's HTTP client; see nodejs/undici#1983 for
  more details.
- Use `AbortSignal` instead of `AbortController` as more modern and
  simpler way to handle timeouts.
2024-03-13 18:26:16 +01:00
36 changed files with 1427 additions and 1896 deletions

View File

@@ -3,6 +3,9 @@ name: checks.external-urls
on:
schedule:
- cron: '0 0 * * 0' # at 00:00 on every Sunday
push:
paths:
- tests/checks/external-urls/**
jobs:
run-check:

View File

@@ -35,8 +35,8 @@ Key attributes of a good script:
## 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`.
- Use archived links by using [archive.org](https://archive.org) or [archive.today](https://archive.today).
- Format archive.today links fully, for example: `https://archive.today/YYYYMMDDhhmmss/https://privacy.sexy`.
- Explain the default behavior if the script is not executed.
## Shared functions

View File

@@ -1,13 +1,8 @@
/* eslint-disable no-template-curly-in-string */
const { join } = require('node:path');
const { readdirSync } = require('fs');
const { electronBundled, electronUnbundled } = require('./dist-dirs.json');
/**
* @type {import('electron-builder').Configuration}
* @see https://www.electron.build/configuration/configuration
*/
module.exports = {
// Common options
publish: {
@@ -19,9 +14,7 @@ module.exports = {
output: electronBundled,
},
extraMetadata: {
main: findMainEntryFile(
join(electronUnbundled, 'main'), // do not `path.resolve`, it expects a relative path
),
main: join(electronUnbundled, 'main/index.cjs'), // do not `path.resolve`, it expects a relative path
},
// Windows
@@ -48,15 +41,3 @@ module.exports = {
artifactName: '${name}-${version}.${ext}',
},
};
/**
* Finds by accommodating different JS file extensions and module formats.
*/
function findMainEntryFile(parentDirectory) {
const files = readdirSync(parentDirectory);
const entryFile = files.find((file) => /^index\.(cjs|mjs|js)$/.test(file));
if (!entryFile) {
throw new Error(`Main entry file not found in ${parentDirectory}.`);
}
return join(parentDirectory, entryFile);
}

View File

@@ -14,7 +14,7 @@ const ELECTRON_DIST_SUBDIRECTORIES = {
renderer: resolveElectronDistSubdirectory('renderer'),
};
process.env.ELECTRON_ENTRY = resolve(ELECTRON_DIST_SUBDIRECTORIES.main, 'index.mjs');
process.env.ELECTRON_ENTRY = resolve(ELECTRON_DIST_SUBDIRECTORIES.main, 'index.cjs');
export default defineConfig({
main: getSharedElectronConfig({
@@ -54,23 +54,13 @@ function getSharedElectronConfig(options: {
},
rollupOptions: {
output: {
format: 'es',
// 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',
// Mark: electron-esm-support
// This is needed so `type="module"` works
entryFileNames: '[name].cjs',
},
},
},
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',
],
})],
plugins: [externalizeDepsPlugin()],
define: {
...getClientEnvironmentVariables(),
},

898
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -37,7 +37,7 @@
"@juggle/resize-observer": "^3.4.0",
"@types/markdown-it": "^13.0.7",
"ace-builds": "^1.30.0",
"electron-log": "^5.1.2",
"electron-log": "^5.0.1",
"electron-progressbar": "^2.1.0",
"electron-updater": "^6.1.4",
"file-saver": "^2.0.5",
@@ -58,8 +58,8 @@
"@vue/test-utils": "^2.4.1",
"autoprefixer": "^10.4.16",
"cypress": "^13.3.1",
"electron": "^29.1.4",
"electron-builder": "^24.13.3",
"electron": "^27.0.0",
"electron-builder": "^24.6.4",
"electron-devtools-installer": "^3.2.0",
"electron-icon-builder": "^2.0.1",
"electron-vite": "^2.1.0",
@@ -82,7 +82,7 @@
"tslib": "^2.6.2",
"typescript": "^5.3.3",
"vite": "^5.1.6",
"vitest": "^1.3.1",
"vitest": "^0.34.6",
"vue-tsc": "^1.8.19",
"yaml-lint": "^1.7.0"
},

View File

@@ -44,8 +44,8 @@ function getBuildVerificationConfigs() {
'--electron-unbundled': {
printDistDirScriptArgument: '--electron-unbundled',
filePatterns: [
/main[/\\]index\.(cjs|mjs|js)/,
/preload[/\\]index\.(cjs|mjs|js)/,
/main[/\\]index\.cjs/,
/preload[/\\]index\.cjs/,
/renderer[/\\]index\.htm(l)?/,
],
},

View File

@@ -95,7 +95,7 @@ function getLines(code: string): string[] {
/*
Merges inline here-strings to a single lined string with Windows line terminator (\r\n)
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules?view=powershell-7.4#here-strings
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules#here-strings
*/
function mergeHereStrings(code: string) {
const regex = /@(['"])\s*(?:\r\n|\r|\n)((.|\n|\r)+?)(\r\n|\r|\n)\1@/g;

View File

@@ -74,7 +74,7 @@ actions:
- [tcsh source code](https://web.archive.org/web/20221029212024/https://github.com/tcsh-org/tcsh).
[1]: https://web.archive.org/web/20221029134950/https://linux.die.net/man/1/tcsh "tcsh(1) - Linux man page | linux.die.net"
[2]: https://web.archive.org/web/20221029135007/https://books.google.com/books?id=LyDP5b2xzaMC&pg=PA56#v=onepage&q&f=false "Sams Teach Yourself FreeBSD in 24 Hours - Michael Urban, Brian Tiemann - Google Books | books.google.com"
[2]: https://web.archive.org/web/20221029135041/https://books.google.com/books?id=LyDP5b2xzaMC&pg=PA56 "Sams Teach Yourself FreeBSD in 24 Hours - Michael Urban, Brian Tiemann - Google Books | books.google.com"
call:
function: DeleteFileFromUserAndRootHome
parameters:
@@ -1733,7 +1733,7 @@ actions:
See also:
- [Source code for the Ubuntu Report tool | github.com](https://web.archive.org/web/20221029221854/https://github.com/ubuntu/ubuntu-report/)
- [Statistics gathered and visualized | ubuntu.com/desktop/statistics](https://web.archive.org/web/20221029221910/https://ubuntu.com/desktop/statistics)
- [ubuntu-devel mailing list thread where ubuntu-report was first proposed | lists.ubuntu.com](https://web.archive.org/web/20221029162523/https://lists.ubuntu.com/archives/ubuntu-devel/2018-February/040139.html)
- [ubuntu-devel mailing list thread where ubuntu-report was first proposed, | lists.ubuntu.com ](https://web.archive.org/web/20221029221924/https://lists.ubuntu.com/archives/ubuntu-devel/2018-February/040139.html)
[1]: https://web.archive.org/web/20221029162505/https://github.com/ubuntu/ubuntu-report/blob/30e902ebc17e4e10d83392d7cd3dc05fc9e35cc4/README.md "ubuntu-report/README.md at master · ubuntu/ubuntu-report | github.com"
[2]: https://web.archive.org/web/20221029162538/https://github.com/ubuntu/ubuntu-report/blob/8e6030ff9bbeacacf41a9b58ea638a5c9a6f864d/README.md "More diagnostics data from desktop | lists.ubuntu.com"
@@ -1974,10 +1974,10 @@ actions:
Read more about Zeitgeist:
- [Official website | zeitgeist.freedesktop.org](https://web.archive.org/web/20221029150843/https://zeitgeist.freedesktop.org/)
- [Official website | zeitgeist.freedesktop.org](https://web.archive.org/web/20221029222739/https://zeitgeist.freedesktop.org/)
- [Wikipedia article | en.wikipedia.org](https://web.archive.org/web/20221029222921/https://en.wikipedia.org/wiki/Zeitgeist_%28free_software%29)
- [Launchpad project page | launchpad.net](https://web.archive.org/web/20221029223026/https://launchpad.net/zeitgeist/)
- [ArchWiki article | wiki.archlinux.org](https://web.archive.org/web/20221029164539/https://wiki.archlinux.org/title/Zeitgeist)
- [ArchWiki article | wiki.archlinux.org](https://web.archive.org/web/20221029223033/https://wiki.archlinux.org/title/Zeitgeist)
[1]: https://web.archive.org/web/20221029163704/https://packages.debian.org/en/sid/libdevel/libzeitgeist-2.0-dev "libzeitgeist-2.0-dev | Debian Packages | packages.debian.org"
[2]: https://web.archive.org/web/20221029163817/https://gitlab.gnome.org/crvi/gnome-activity-journal "crvi / GNOME Activity Journal · GitLab | gitlab.gnome.org"
@@ -2116,7 +2116,7 @@ actions:
[3]: https://web.archive.org/web/20221029170026/https://packages.ubuntu.com/bionic/all/network-manager-config-connectivity-ubuntu/filelist "Ubuntu - File list of package network-manager-config-connectivity-ubuntu/bionic/all | packages.ubuntu.com"
[4]: https://web.archive.org/web/20221029170108/https://github.com/pop-os/connectivity/blob/master/debian/20-connectivity-pop.conf "connectivity/20-connectivity-pop.conf at master · pop-os/connectivity | github.com"
[5]: https://web.archive.org/web/20221029170202/https://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/contrib/fedora/rpm/20-connectivity-fedora.conf "20-connectivity-fedora.conf\rpm\fedora\contrib - NetworkManager/NetworkManager - Network connection manager and user applications | reedesktop.org"
[6]: https://archive.ph/2023.12.06-185917/https://pkgs.org/download/NetworkManager-config-connectivity-fedora "Networkmanager-config-connectivity-fedora Download (RPM) | pkgs.org"
[6]: https://web.archive.org/web/20221029170207/https://fedora.pkgs.org/35/fedora-updates-testing-x86_64/NetworkManager-config-connectivity-fedora-1.32.12-1.fc35.noarch.rpm.html "NetworkManager-config-connectivity-fedora | fedora.pkgs.org"
call:
function: RunIfCommandExists
parameters:
@@ -2202,7 +2202,7 @@ actions:
- Diagnostic information about your system and usage is sent to Microsoft servers [3].
- Your usage data and data about feature performance [3].
[1]: https://web.archive.org/web/20221029142001/https://en.wikipedia.org/wiki/Visual_Studio_Code "Visual Studio Code - Wikipedia | en.wikipedia.org"
[1]: https://web.archive.org/web/20221029170818/https://en.wikipedia.org/wiki/Visual_Studio_Code "Visual Studio Code - Wikipedia | en.wikipedia.org"
[2]: https://web.archive.org/web/20221029170840/https://code.visualstudio.com/updates/v1_26#_offline-mode "Visual Studio Code July 2018 | code.visualstudio.com"
[3]: https://web.archive.org/web/20221029171138/https://code.visualstudio.com/docs/getstarted/telemetry "Visual Studio Code Telemetry | code.visualstudio.com"
children:
@@ -2697,7 +2697,7 @@ actions:
[2]: https://web.archive.org/web/20231003094154/https://bugzilla.mozilla.org/show_bug.cgi?id=1746646 "1746646 - (tcp-mochitests) [meta] Make mochitests work with TCP enabled (cookieBehavior = 5) | bugzilla.mozilla.org"
[3]: https://web.archive.org/web/20230918172155/https://developer.mozilla.org/en-US/docs/Web/Privacy/State_Partitioning#disable_dynamic_state_partitioning "State Partitioning - Privacy on the web | MDN"
[4]: https://web.archive.org/web/20231003094207/https://bugzilla.mozilla.org/show_bug.cgi?id=1649876#c5 "1649876 - Migrate FPI users to dFPI | bugzilla.mozilla.org"
[5]: https://web.archive.org/web/20231207105610/https://blog.mozilla.org/en/products/firefox/firefox-rolls-out-total-cookie-protection-by-default-to-all-users-worldwide/ "Firefox Rolls Out Total Cookie Protection By Default"
[5]: https://blog.mozilla.org/en/products/firefox/firefox-rolls-out-total-cookie-protection-by-default-to-all-users-worldwide/ "Firefox Rolls Out Total Cookie Protection By Default"
[6]: https://web.archive.org/web/20231003094350/https://bugzilla.mozilla.org/show_bug.cgi?id=1631676#c25 "1631676 - Disable dfpi when privacy.firstparty.isolate=true | bugzilla.mozilla.org"
call:
function: AddFirefoxPrefs
@@ -2887,7 +2887,7 @@ actions:
setting [4].
[1]: https://web.archive.org/web/20221015102124/https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/internals/preferences.html "Preferences and Defines — Firefox Source Docs documentation | firefox-source-docs.mozilla.org"
[2]: https://web.archive.org/web/20221015102338/https://searchfox.org/mozilla-central/source/modules/libpref/Preferences.cpp#3213
[2]: https://web.archive.org/web/20221015102305/https://searchfox.org/mozilla-central/source/modules/libpref/Preferences.cpp#3213
[3]: https://web.archive.org/web/20221015102419/https://bugzilla.mozilla.org/show_bug.cgi?id=1422689#c1
[4]: https://web.archive.org/web/20221015102604/https://stigviewer.com/stig/mozilla_firefox/2020-12-10/finding/V-223170
call:
@@ -3173,7 +3173,7 @@ actions:
portal is in place and blocking traffic, this feature prevents all other connection attempts,
possibly revealing your usage habits.
See also: [Captive portal | Wikipedia](https://web.archive.org/web/20221029163002/https://en.wikipedia.org/wiki/Captive_portal).
See also: [Captive portal | Wikipedia](https://web.archive.org/web/20221029223534/https://en.wikipedia.org/wiki/Captive_portal).
This script sets `network.captive-portal-service.enabled` to 'false', thereby disabling automatic
connections [1].
@@ -3207,7 +3207,7 @@ actions:
There have been concerns about the potential for Google Safe Browsing to be used for censorship
in the future, although this has not occurred as of yet [3].
[1]: https://web.archive.org/web/20221026164502/https://wiki.mozilla.org/Security/Safe_Browsing "Security/Safe Browsing - MozillaWiki | wiki.mozilla.org"
[1]: https://web.archive.org/web/20221025192643/https://wiki.mozilla.org/Security/Safe_Browsing "Security/Safe Browsing - MozillaWiki | wiki.mozilla.org"
[2]: https://web.archive.org/web/20221025193000/https://support.mozilla.org/en-US/kb/how-does-phishing-and-malware-protection-work#w_what-information-is-sent-to-mozilla-or-its-partners-when-phishing-and-malware-protection-is-enabled
[3]: https://web.archive.org/web/20221025192516/https://www.usnews.com/opinion/articles/2016-06-22/google-is-the-worlds-biggest-censor-and-its-power-must-be-regulated "Google Is the World's Biggest Censor and Its Power Must Be Regulated | usnews.com"
children:
@@ -3226,7 +3226,7 @@ actions:
If this blocking is removed, the user should be knowledgeable about the potential risks and will take precautions.
[1]: https://web.archive.org/web/20221026164502/https://wiki.mozilla.org/Security/Safe_Browsing#Prefs "Security/Safe Browsing - MozillaWiki | wiki.mozilla.org"
[1]: https://web.archive.org/web/20221025192643/https://wiki.mozilla.org/Security/Safe_Browsing#Prefs "Security/Safe Browsing - MozillaWiki | wiki.mozilla.org"
[2]: https://web.archive.org/web/20230811024650/https://blog.mozilla.org/addons/2020/08/24/introducing-a-scalable-add-ons-blocklist/ "Introducing a scalable add-ons blocklist | Mozilla Add-ons Community Blog"
call:
function: AddFirefoxPrefs
@@ -3286,7 +3286,7 @@ actions:
It is active by default [2].
[1]: https://web.archive.org/web/20221026164502/https://wiki.mozilla.org/Security/Safe_Browsing#Prefs "Security/Safe Browsing - MozillaWiki | wiki.mozilla.org"
[1]: https://web.archive.org/web/20221025192643/https://wiki.mozilla.org/Security/Safe_Browsing#Prefs "Security/Safe Browsing - MozillaWiki | wiki.mozilla.org"
[2]: https://web.archive.org/web/20221029173442/https://github.com/mozilla/policy-templates/blob/master/README.md#preferences "policy-templates/README.md at master · mozilla/policy-templates · GitHub | github.com"
call:
function: AddFirefoxPrefs

View File

@@ -108,7 +108,7 @@ actions:
name: Clear user activity audit logs (login, logout, authentication, etc.)
docs:
- https://papers.put.as/papers/macosx/2012/Mac_Log_Analysis_Sarah_Edwards_DFIRSummit2012.pdf
- https://web.archive.org/web/20240314054514/https://bpb-us-e1.wpmucdn.com/sites.psu.edu/dist/4/24696/files/2016/06/psumac2016-19-osxlogs_macadmins_2016.pdf
- http://macadmins.psu.edu/wp-content/uploads/sites/24696/2016/06/psumac2016-19-osxlogs_macadmins_2016.pdf
code: |-
sudo rm -rfv /var/audit/*
sudo rm -rfv /private/var/audit/*
@@ -171,7 +171,7 @@ actions:
-
name: Clear Safari last session (open tabs) history
docs:
- https://web.archive.org/web/20240314061752/https://apple.stackexchange.com/questions/374099/where-does-safari-store-the-open-tabs/374116#374116
- https://apple.stackexchange.com/a/374116
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-7127
code: rm -f ~/Library/Safari/LastSession.plist
-
@@ -191,7 +191,7 @@ actions:
name: Clear Safari webpage previews (thumbnails)
docs:
- https://davidkoepi.wordpress.com/2013/04/20/safariforensic/
- https://archive.ph/2024.03.14-100910/https://www.reddit.com/r/apple/comments/18lp92/your_apple_computer_keeps_a_screen_shot_of_nearly/?rdt=59921
- https://www.reddit.com/r/apple/comments/18lp92/your_apple_computer_keeps_a_screen_shot_of_nearly/
code: rm -rfv ~/Library/Caches/com.apple.Safari/Webpage\ Previews
-
name: Clear Safari history copy
@@ -204,8 +204,8 @@ actions:
-
name: Clear Safari cookies
docs:
- https://web.archive.org/web/20240314132018/https://community.spiceworks.com/t/understanding-the-safari-cookies-binarycookies-file-format/928827
- https://web.archive.org/web/20240314060318/https://link.springer.com/content/pdf/10.1007/0-387-36891-4_13.pdf
- https://www.toolbox.com/tech/operating-systems/blogs/understanding-the-safari-cookiesbinarycookies-file-format-010712/
- https://link.springer.com/content/pdf/10.1007/0-387-36891-4_13.pdf
code: |-
rm -f ~/Library/Cookies/Cookies.binarycookies
# Used before Safari 5.1
@@ -520,7 +520,7 @@ actions:
you'll be prompted to grant or deny permission. It's a proactive step to ensure that your sensitive information
or system services are accessed only with your current and informed consent.
children:
# Main documentation: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services
# Main documentation: https://archive.ph/26Hlq (https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services)
-
name: Clear **"All"** permissions
docs: |-
@@ -536,7 +536,7 @@ actions:
This script resets permissions for camera access [1].
It ensures no application can access the system camera without explicit user permission, protecting against unauthorized surveillance and data breaches.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -547,7 +547,7 @@ actions:
This script resets permissions for microphone access [1].
It revokes all granted access to the microphone, protecting against eavesdropping and unauthorized audio recording by applications.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -558,7 +558,7 @@ actions:
This script resets permissions for accessibility features [1].
It revokes application access to accessibility services, preventing misuse and ensuring these features are used only with user consent.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -569,7 +569,7 @@ actions:
This script resets permissions for screen capture [1].
It ensures applications cannot capture screen content without user authorization, protecting sensitive information displayed on the screen.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -580,7 +580,7 @@ actions:
This script resets permissions for accessing reminders information managed by the Reminders app [1].
It ensures applications cannot access or modify reminders data without explicit user permission, maintaining the privacy of personal reminders.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -591,7 +591,7 @@ actions:
This script resets permissions for accessing the pictures managed by the Photos app [1].
It revokes all permissions granted to applications, safeguarding personal photos and media from unauthorized access.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -602,7 +602,7 @@ actions:
This script resets permissions for accessing the calendar information managed by the Calendar app [1].
It ensures that applications cannot access calendar data without user consent, protecting personal and sensitive calendar information.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -614,7 +614,7 @@ actions:
Full disk access allows the application access to all protected files, including system administration files [1].
It revokes broad file access from applications, significantly reducing the risk of data exposure and enhancing overall system security.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -626,7 +626,7 @@ actions:
The contact information managed by the Contacts app [1].
It ensures that applications cannot access the user's contact list without explicit permission, maintaining the confidentiality of personal contacts.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -637,7 +637,7 @@ actions:
This script resets permissions for accessing the Desktop folder [1].
It revokes application access to files on the desktop, protecting personal and work-related documents from unauthorized access.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -648,7 +648,7 @@ actions:
This script resets permissions for accessing the Documents folder [1].
It prevents applications from accessing files in this folder without user consent, safeguarding important and private documents.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -659,7 +659,7 @@ actions:
This script resets permissions for accessing the Downloads folder [1].
It ensures that applications cannot access downloaded files without user authorization, protecting downloaded content from misuse.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -670,7 +670,7 @@ actions:
This script resets permissions for Apple Events [1].
It revokes permissions for applications to send restricted Apple Events to other processes [1], enhancing privacy and security.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -681,7 +681,7 @@ actions:
This script resets permissions for File Provider Presence [1].
It revokes the ability of File Provider applications to know when the user is accessing their managed files [1], enhancing user privacy.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -692,7 +692,7 @@ actions:
This script resets "ListenEvent" permissions [1].
It revokes application access to listen to system events [1], preventing unauthorized monitoring of user interactions with the system.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -703,7 +703,7 @@ actions:
This script resets permissions for accessing the Media Library [1].
It ensures that applications cannot access Apple Music, music and video activity, and the media library [1] without user consent.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -714,7 +714,7 @@ actions:
This script resets permissions for sending "PostEvent" [1].
It prevents applications from using CoreGraphics APIs to send system events [1], safeguarding against potential misuse.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -726,7 +726,7 @@ actions:
This script resets permissions for using Speech Recognition [1].
It revokes application access to the speech recognition facility and sending speech data to Apple [1], protecting user privacy.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -737,7 +737,7 @@ actions:
This script resets permissions for modifying other apps [1].
It prevents applications from updating or deleting other apps [1], maintaining system integrity and user control.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -748,7 +748,7 @@ actions:
This script resets permissions for accessing application data [1].
It revokes application access to specific application data, enhancing privacy and data security.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -759,7 +759,7 @@ actions:
This script resets permissions for accessing files on network volumes [1].
It ensures applications cannot access network files without user authorization.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -770,7 +770,7 @@ actions:
This script resets permissions for accessing files on removable volumes [1].
It protects data on external drives from unauthorized application access.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -781,7 +781,7 @@ actions:
This script resets permissions for accessing system administration files [1].
It enhances system security by restricting application access to critical system files.
[1]: https://archive.ph/2023.11.24-170934/https://developer.apple.com/documentation/devicemanagement/privacypreferencespolicycontrol/services "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
[1]: https://archive.ph/26Hlq "PrivacyPreferencesPolicyControl.Services | Apple Developer Documentation | apple.com"
call:
function: ResetServicePermissions
parameters:
@@ -877,7 +877,7 @@ actions:
There is also `WelcomeScreenPromo.PromoOff` setting that's pre-configured to `1` (`no` as
default). It's undocumented but still kept disabled by this script.
[1]: https://web.archive.org/web/20240314062932/https://forum.parallels.com/threads/unable-to-process-the-upgrade-request.345603/ "Unable to process the upgrade request | Parallels Forums | forum.parallels.com"
[1]: https://web.archive.org/save/https://forum.parallels.com/threads/unable-to-process-the-upgrade-request.345603/ "Unable to process the upgrade request | Parallels Forums | forum.parallels.com"
[2]: https://web.archive.org/web/20221012151800/https://kb.parallels.com/114422 "How do I turn off notifications in Parallels Desktop and Parallels Access? | Knowledge Base | parallels.com"
code: |-
defaults write 'com.parallels.Parallels Desktop' 'ProductPromo.ForcePromoOff' -bool yes
@@ -988,16 +988,16 @@ actions:
recommend: strict
docs:
- https://github.com/privacysexy-forks/starter/blob/master/system/siri.sh
- https://web.archive.org/web/20201002133713/https://machippie.github.io/system/
- https://machippie.github.io/system/
code: defaults write com.apple.assistant.backedup 'Use device speaker for TTS' -int 3
revertCode: defaults write com.apple.assistant.backedup 'Use device speaker for TTS' -int 2
-
name: Disable Siri services (Siri and assistantd)
recommend: strict
docs:
- https://web.archive.org/web/20240314060540/https://apple.stackexchange.com/questions/57514/what-is-assistantd
- https://archive.ph/2024.03.14-055010/https://community.jamf.com/t5/jamf-pro/kill-siri/td-p/171543
- https://web.archive.org/web/20240314060501/https://apple.stackexchange.com/questions/258816/how-to-completely-disable-siri-on-sierra/370426#370426
- https://apple.stackexchange.com/questions/57514/what-is-assistantd
- https://www.jamf.com/jamf-nation/discussions/22757/kill-siri#responseChild137563
- https://apple.stackexchange.com/a/370426
# To see status: • `launchctl print-disabled system` • `launchctl print-disabled user/$UID` • `launchctl print-disabled gui/$UID`
code: |-
launchctl disable "user/$UID/com.apple.assistantd"
@@ -1021,20 +1021,10 @@ actions:
fi
-
name: Disable "Do you want to enable Siri?" pop-up
docs: |-
This script stops the "Enable Siri" pop-up [1] from appearing the first time a user logs into macOS [2].
Introduced in macOS version 10.12 [2], this pop-up asks, "Do you want to enable Siri?" [1]
which could lead to Siri being enabled unintentionally.
This script configures the `com.apple.SetupAssistant!DidSeeSiriSetup` setting to suppress this pop-up [1] [2] [3] [4].
This command tells the system that the Siri setup is complete, preventing the pop-up in future sessions and
enhancing privacy by avoiding unintended Siri activation.
[1]: https://archive.ph/2024.03.14-053325/https://discussions.apple.com/thread/7694127?answerId=30752577022&sortBy=best%2330752577022 "macOS keeps nagging me about enabling Siri - Apple Community | discussions.apple.com"
[2]: https://web.archive.org/web/20240314052600/https://derflounder.wordpress.com/2016/09/20/supressing-siri-pop-up-windows-on-macos-sierra/ "Suppressing Siri pop-up windows on macOS Sierra | Der Flounder"
[3]: https://web.archive.org/web/20240314052901/https://windowsreport.com/mac/siri-keeps-popping-up/ "Siri keeps popping up on Mac? Here's how to easily fix that • MacTips | windowsreport.com"
[4]: https://web.archive.org/web/20240314052247/https://community.jamf.com/t5/jamf-pro/disable-siri-setup-assistant-in-macos-sierra/m-p/205836/highlight/true#M194536 "Solved: Re: Disable Siri setup assistant in macOS Sierra - Jamf Nation Community - 205834 | community.jamf.com"
docs:
- https://discussions.apple.com/thread/7694127?answerId=30752577022#30752577022
- https://windowsreport.com/mac/siri-keeps-popping-up/
- https://www.jamf.com/jamf-nation/discussions/21783/disable-siri-setup-assistant-in-macos-sierra#responseChild131588
code: defaults write com.apple.SetupAssistant 'DidSeeSiriSetup' -bool True
revertCode: defaults delete com.apple.SetupAssistant 'DidSeeSiriSetup'
-
@@ -1094,7 +1084,7 @@ actions:
by default.
[1]: https://web.archive.org/web/20230731152633/https://www.apple.com/legal/privacy/data/en/apple-advertising/ "Legal - Apple Advertising & Privacy - Apple"
[2]: https://web.archive.org/web/20220805052411/https://support.apple.com/en-sg/guide/mac-help/mh32356/mac "Change Privacy preferences on Mac - Apple Support (SG)"
[2]: https://web.archive.org/web/20220805052411/https://support.apple.com/en-sg/guide/mac-help/mh32356/mac: "Change Privacy preferences on Mac - Apple Support (SG)"
[3]: https://web.archive.org/web/20230731155827/https://developer.apple.com/documentation/devicemanagement/restrictions "Restrictions | Apple Developer Documentation"
[4]: https://web.archive.org/web/20230731155653/https://paper.bobylive.com/Security/CIS/CIS_Apple_macOS_11_0_Big_Sur_Benchmark_v2_0_0.pdf "CIS Apple macOS 11.0 Big Sur Benchmark"
[5]: https://web.archive.org/web/20230731155131/https://developer.apple.com/documentation/adsupport/asidentifiermanager/1614151-advertisingidentifier "advertisingIdentifier | Apple Developer Documentation"
@@ -1290,7 +1280,7 @@ actions:
# OS tracks downloaded files with help of quarantine-aware applications
# (such as Safari, Chrome) adding quarantine extended attributes to files.
# then OS warns and asks if you really want to open it
docs: https://web.archive.org/web/20210319081714/https://support.apple.com/en-gb/HT202491
docs: https://support.apple.com/en-gb/HT202491
children:
-
category: Clean File Quarantine from downloaded files
@@ -1401,7 +1391,7 @@ actions:
name: Disable Gatekeeper's automatic reactivation
docs:
- https://osxdaily.com/2015/11/05/stop-gatekeeper-auto-rearm-mac-os-x/
- https://web.archive.org/web/20230327050142/https://www.cnet.com/tech/computing/how-to-disable-gatekeeper-permanently-on-os-x/
- https://www.cnet.com/tech/computing/how-to-disable-gatekeeper-permanently-on-os-x/
code: sudo defaults write /Library/Preferences/com.apple.security GKAutoRearm -bool true
revertCode: sudo defaults write /Library/Preferences/com.apple.security GKAutoRearm -bool false
-
@@ -1460,19 +1450,13 @@ actions:
revertCode: sudo defaults write /Library/Preferences/com.apple.security.libraryvalidation.plist 'DisableLibraryValidation' -bool false
-
category: Disable automatic updates
docs: |-
This category contains scripts to disable automatic operating system updates.
Disabling automatic updates gives users full control over when and which updates are applied to their system.
It improves privacy by preventing unwanted data collection, new vulnerabilities and unapproved changes to system settings.
> **Caution**:
> Disabling automatic updates can leave your system vulnerable to unpatched exploits.
> Manually check and and apply updates to stay protected.
docs:
- https://developer.apple.com/documentation/devicemanagement/deviceinformationresponse/queryresponses/osupdatesettings
- https://macadminsdoc.readthedocs.io/en/master/Profiles-and-Settings/OS-X-Updates.html
children:
-
name: Disable automatic checks for updates
docs: https://archive.ph/2024.03.21-180353/https://developer.apple.com/documentation/devicemanagement/softwareupdate
docs: https://developer.apple.com/documentation/devicemanagement/softwareupdate
code: |-
# For OS X Yosemite and newer (>= 10.10)
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate 'AutomaticCheckEnabled' -bool false
@@ -1481,7 +1465,7 @@ actions:
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate 'AutomaticCheckEnabled' -bool true
-
name: Disable automatic downloads for updates
docs: https://archive.ph/2024.03.21-180353/https://developer.apple.com/documentation/devicemanagement/softwareupdate
docs: https://developer.apple.com/documentation/devicemanagement/softwareupdate
code: |-
# For OS X Yosemite and newer (>= 10.10)
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate 'AutomaticDownload' -bool false
@@ -1490,41 +1474,12 @@ actions:
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate 'AutomaticDownload' -bool true
-
name: Disable automatic installation of macOS updates
docs: |-
This script stops macOS from automatically installing updates.
This script improves privacy by reducing unwanted data collection and ensuring updates don't change
settings or data without your approval.
The Center for Internet Security (CIS) advises against automatic updates in scenarios where changes require
thorough testing and approval processes to avoid operational disruptions [1] [2] [3] [4].
This script configures following to stop macOS from installing updates automatically:
1. `/Library/Preferences/com.apple.commerce!AutoUpdateRestartRequired`:
This preference stops the system from automatically installing macOS updates [1] [2] [3] [4] [5] [6] [7] [8].
By doing this, updates will only be installed when you decide, giving you a chance to check them first [1] [2] [3] [4] [5] [6] [7] [8].
This setting applies to OS X Yosemite through macOS High Sierra [7] [9].
2. `/Library/Preferences/com.apple.commerce!AutomaticallyInstallMacOSUpdates`:
Changing this setting stops macOS from installing updates automatically [3] [5] [9] [10], giving you control over when to update.
If restricts the *Install macOS Updates* option and prevents the user from changing the option [10].
While this setting enhances privacy, it's generally not advised by NIST due to potential security risks [9].
This setting applies to macOS Mojave and newer versions [9].
> **Caution**: Disabling automatic updates requires you to manually check and apply updates to stay protected against security threats [1] [2] [3] [4].
[1]: https://web.archive.org/web/20240321165149/https://www.tenable.com/audits/items/CIS_Apple_macOS_10.12_v1.1.0_Level_1.audit:e02dfdd6bec9556a3ce537f60b91b549 "CIS Apple macOS 10.12 L1 v1.1.0 | 1.5 Enable OS X update installs | Tenable®"
[2]: https://web.archive.org/web/20240321165851/https://paper.bobylive.com/Security/CIS/CIS_Apple_macOS_10_13_Benchmark_v1_1_0---PDF.pdf "CIS Apple macOS 10.13 Benchmark v1.1.0 | paper.bobylive.com"
[3]: https://web.archive.org/web/20240321170400/https://www.tenable.com/audits/items/CIS_Apple_macOS_13.0_Ventura_v1.0.0_L1.audit:fe03c59a39c7c949507ff20d07f89993 "1.4 Ensure Install of macOS Updates Is Enabled | Tenable® | www.tenable.com"
[4]: https://web.archive.org/web/20240321170036/https://paper.bobylive.com/Security/CIS/CIS_Apple_macOS_10_14_Benchmark_v1_4_0_PDF.pdf "CIS Apple macOS 10.14 Benchmark v1.4.0 | paper.bobylive.com"
[5]: https://web.archive.org/web/20240321164917/https://www.ncsc.gov.uk/files/macos_provisioning_script.sh_.txt "macOS provisioning script | UK National Cyber Security Centre | www.ncsc.gov.uk"
[6]: https://web.archive.org/web/20240321165118/https://macadminsdoc.readthedocs.io/en/master/Profiles-and-Settings/OS-X-Updates.html "macOS Updates — MacAdmins Community Documentation documentation | macadminsdoc.readthedocs.io"
[7]: https://web.archive.org/web/20240321165304/https://derflounder.wordpress.com/2014/12/29/managing-automatic-app-store-and-os-x-update-installation-on-yosemite/ "Managing automatic App Store and OS X update installation on Yosemite | Der Flounder | derflounder.wordpress.com"
[8]: https://web.archive.org/web/20240321170034/https://krypted.com/mac-os-x/app-store-preferences-set-server-5-4-macos-high-sierra/ "App Store Preferences To Set In On Server 5.4 for macOS High Sierra krypted | krypted.com"
[9]: https://web.archive.org/web/20240321170251/https://derflounder.wordpress.com/2018/12/28/enabling-automatic-macos-software-updates-for-os-x-yosemite-through-macos-mojave/ "Enabling automatic macOS software updates for OS X Yosemite through macOS Mojave | Der Flounder | derflounder.wordpress.com"
[10]: https://archive.ph/2024.03.21-180353/https://developer.apple.com/documentation/devicemanagement/softwareupdate "SoftwareUpdate | Apple Developer Documentation | developer.apple.com"
[11]: https://web.archive.org/web/20240321165931/https://csrc.nist.gov/CSRC/media/Projects/national-vulnerability-database/documents/CCE/CCE-macos_monterey.xls "CCE-91129-7 | CCE-macos_monterey.xls | Sheet 1 - NIST Computer Security Resource Center | csrc.nist.gov"
docs:
# References for AutoUpdateRestartRequired
- https://kb.vmware.com/s/article/2960635
- https://derflounder.wordpress.com/2018/12/28/enabling-automatic-macos-software-updates-for-os-x-yosemite-through-macos-mojave/
# References for AutomaticallyInstallMacOSUpdates
- https://developer.apple.com/documentation/devicemanagement/softwareupdate
code: |-
# For OS X Yosemite through macOS High Sierra (>= 10.10 && < 10.14)
sudo defaults write /Library/Preferences/com.apple.commerce 'AutoUpdateRestartRequired' -bool false
@@ -1537,44 +1492,9 @@ actions:
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate 'AutomaticallyInstallMacOSUpdates' -bool true
-
name: Disable automatic app updates from the App Store
docs: |-
This script disables automatic app updates [1] [2] [3] [4] from the App Store [5] [6] [7] [8] [9] [10] [11] [12] [13].
It prevents automatic installation of application updates as soon as they become available from Apple [2] [3] [6] [9] [11] [12] [13].
Thus, applications are updated only when you choose to do so [5].
Disabling automatic updates prevents unexpected app behavior or settings changes.
It helps you to maintain your current app configurations and privacy settings.
It also protects against potential zero-day vulnerabilities in your apps.
This gives you the ability to choose which updates to install and when, enabling you to review the details of updates before deciding to proceed.
The script modifies the following settings:
1. `/Library/Preferences/com.apple.commerce!AutoUpdate`:
Disables automated app updates [1] [2] [3] [6] [9] [10] [13] from the App Store [7] [8].
This setting applies to OS X Yosemite and newer versions [1].
2. `/Library/Preferences/com.apple.SoftwareUpdate!AutomaticallyInstallAppUpdates`:
Stops the automatic installation of app updates [1] [4] from App Store [9] [10] [11] [12] [13].
It deselects the *Install app updates from the App Store* option and prevents the user from changing the option [10].
While this setting enhances privacy, it's generally not advised by NIST due to potential security risks [4].
This setting applies to macOS Mojave and newer versions [1].
> **Caution**:
> Disabling app updates means you should manually check for and install important security patches for every application
> to protect against vulnerabilities [2] [3] [5] [6] [9] [11] [12] [13].
[1]: https://web.archive.org/web/20240321170251/https://derflounder.wordpress.com/2018/12/28/enabling-automatic-macos-software-updates-for-os-x-yosemite-through-macos-mojave/ "Enabling automatic macOS software updates for OS X Yosemite through macOS Mojave | Der Flounder | derflounder.wordpress.com"
[2]: https://web.archive.org/web/20240321190032/https://www.irs.gov/pub/irs-utl/safeguards-scsem-macosx-v6-1-093021.xlsx "SCSEM OSX 10.14 | Internal Revenue Service Office of Safeguards | www.irs.gov"
[3]: https://web.archive.org/web/20240321170036/https://paper.bobylive.com/Security/CIS/CIS_Apple_macOS_10_14_Benchmark_v1_4_0_PDF.pdf "CIS Apple macOS 10.14 Benchmark v1.4.0 | paper.bobylive.com"
[5]: https://web.archive.org/web/20240321190244/https://github-wiki-see.page/m/edamametechnologies/threatmodels/wiki/threatmodel-macOS-EN "threatmodel macOS EN - edamametechnologies/threatmodels GitHub Wiki | github-wiki-see.page"
[6]: https://web.archive.org/web/20240321190315/https://www.tenable.com/audits/items/CIS_Apple_macOS_14.0_Sonoma_v1.0.0_L1.audit:66d3b86318384ba7947a3409e0c6e902 "1.5 Ensure Install Application Updates from the App Store Is E... | Tenable® | www.tenable.com"
[7]: https://web.archive.org/web/20240321165304/https://derflounder.wordpress.com/2014/12/29/managing-automatic-app-store-and-os-x-update-installation-on-yosemite/ "Managing automatic App Store and OS X update installation on Yosemite | Der Flounder | derflounder.wordpress.com"
[8]: https://web.archive.org/web/20240321190410/https://krypted.com/mac-security/app-store-preferences-set-server-5-2-macos-sierra/ "App Store Preferences To Set In On Server 5.2 for macOS Sierra krypted | krypted.com"
[4]: https://web.archive.org/web/20240321165931/https://csrc.nist.gov/CSRC/media/Projects/national-vulnerability-database/documents/CCE/CCE-macos_monterey.xls "CCE-91129-7 | CCE-macos_monterey.xls | Sheet 1 - NIST Computer Security Resource Center | csrc.nist.gov"
[9]: https://web.archive.org/web/20240321190114/https://www.irs.gov/pub/irs-utl/safeguards-scsem-macosx.xlsx "SCSEM OSX 13.0 | Internal Revenue Service Office of Safeguards | www.irs.gov"
[10]: https://archive.ph/2024.03.21-180353/https://developer.apple.com/documentation/devicemanagement/softwareupdate "SoftwareUpdate | Apple Developer Documentation | developer.apple.com"
[11]: https://web.archive.org/web/20240321190122/https://paper.bobylive.com/Security/CIS/CIS_Apple_macOS_12_0_Monterey_Benchmark_v1_0_0.pdf "CIS Apple macOS 12.0 Monterey | CIS Benchmarks | paper.bobylive.com"
[12]: https://web.archive.org/web/20240321190537/https://www.tenable.com/audits/items/CIS_Apple_macOS_11_v2.0.0_L1.audit:55e8759872dce781b8dbc5a3f42e23b9 "1.4 Ensure Installation of App Update Is Enabled | Tenable® | www.tenable.com"
[13]: https://web.archive.org/web/20240321164917/https://www.ncsc.gov.uk/files/macos_provisioning_script.sh_.txt "macOS provisioning script | UK National Cyber Security Centre | www.ncsc.gov.uk"
docs:
- https://kb.vmware.com/s/article/2960635
- https://derflounder.wordpress.com/2018/12/28/enabling-automatic-macos-software-updates-for-os-x-yosemite-through-macos-mojave/
code: |-
# For OS X Yosemite and newer (>= 10.10)
sudo defaults write /Library/Preferences/com.apple.commerce 'AutoUpdate' -bool false
@@ -1587,7 +1507,7 @@ actions:
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate 'AutomaticallyInstallAppUpdates' -bool true
-
name: Disable macOS beta release installation
docs: https://web.archive.org/web/20170106103856/https://support.apple.com/en-gb/HT203018
docs: https://support.apple.com/en-gb/HT203018
code: |-
# For OS X Yosemite and newer (>= 10.10)
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate 'AllowPreReleaseInstallation' -bool false
@@ -1596,7 +1516,7 @@ actions:
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate 'AllowPreReleaseInstallation' -bool true
-
name: Disable automatic installation for configuration data (e.g. XProtect, Gatekeeper, MRT)
docs: https://web.archive.org/web/20240321170251/https://derflounder.wordpress.com/2018/12/28/enabling-automatic-macos-software-updates-for-os-x-yosemite-through-macos-mojave/
docs: https://derflounder.wordpress.com/2018/12/28/enabling-automatic-macos-software-updates-for-os-x-yosemite-through-macos-mojave/
code: |-
# For OS X Yosemite and newer (>= 10.10)
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate 'ConfigDataInstall' -bool false
@@ -1605,47 +1525,12 @@ actions:
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate 'ConfigDataInstall' -bool true
-
name: Disable automatic installation for system data files and security updates
docs: |-
This script stops automatic installations of critical updates [1],
including security [1] [2] [3] [4] [5] [6] [7] and system data file [1] [8] updates.
It improves privacy by providing:
- **Control Over Update Timing**:
Users can review updates before installation to ensure they meet privacy standards and do not introduce
unwanted telemetry or changes.
- **Reduced External Communications**:
Reduces how often it connects to update servers, potentially protection user information.
The script configures the `/Library/Preferences/com.apple.SoftwareUpdate!CriticalUpdateInstall` setting [1] [4] [5] [7] [8].
This action prevents automatic downloads and installations of updates [1].
It also prevents users from changing the Install system data files and security updates option manually [1].
This script is compatible with OS X Yosemite and later versions [6] [8].
The revert script triggers `softwareupdate --background-critical` to install any pending critical updates directly [2] [9].
> **Caution:**
> Only disable automatic updates if you're committed to manually installing them quickly to maintain your computer's security [4] [5] [8].
> It's important to install updates soon to protect your computer. [4] [5] [8].
>
> This script disables:
>
> - Definition updates for **XProtect** and **Gatekeeper** that keep your computer safe from new threats [5].
> - **Rapid Security Response** [10] [11].
> **Rapid Security Responses** are software releases providing important security improvements between standard updates [12].
[1]: https://archive.ph/2024.03.21-180353/https://developer.apple.com/documentation/devicemanagement/softwareupdate "SoftwareUpdate | Apple Developer Documentation | developer.apple.com"
[2]: https://web.archive.org/web/20240321201417/https://derflounder.wordpress.com/2014/12/24/managing-os-xs-automatic-security-updates/ "Managing OS Xs automatic security updates | Der Flounder | derflounder.wordpress.com"
[3]: https://web.archive.org/web/20240321165118/https://macadminsdoc.readthedocs.io/en/master/Profiles-and-Settings/OS-X-Updates.html "macOS Updates — MacAdmins Community Documentation documentation | macadminsdoc.readthedocs.io"
[4]: https://web.archive.org/web/20240321165931/https://csrc.nist.gov/CSRC/media/Projects/national-vulnerability-database/documents/CCE/CCE-macos_monterey.xls "CCE-91129-7 | CCE-macos_monterey.xls | Sheet 1 - NIST Computer Security Resource Center | csrc.nist.gov"
[5]: https://web.archive.org/web/20240321201450/https://paper.bobylive.com/Security/CIS/CIS_Apple_OSX_10_9_Benchmark_v1_3_0.pdf "CIS Apple OSX 10.9 Benchmark | paper.bobylive.com"
[6]: https://web.archive.org/web/20240321201643/https://derflounder.wordpress.com/2014/12/27/managing-automatic-installation-of-configdata-and-security-software-updates-on-yosemite/ "Managing automatic installation of ConfigData and security software updates on Yosemite | Der Flounder | derflounder.wordpress.com"
[7]: https://web.archive.org/web/20240321201652/https://ss64.com/mac/syntax-defaults.html "System preference settings for macOS - macOS - SS64.com | ss64.com"
[8]: https://web.archive.org/web/20240321201436/https://www.tenable.com/audits/items/CIS_OSX_10.10_v1.2.0_L1.audit:97f36c2eaa06045e85a1beff1a76a088 "1.4 Enable system data files and security update installs - 'C... | Tenable® | www.tenable.com"
[9]: https://web.archive.org/web/20240321201406/https://managingosx.wordpress.com/2013/04/30/undocumented-options/ "Undocumented options Managing OS X | managingosx.wordpress.com"
[10]: https://web.archive.org/web/20240321201558/https://www.intuneirl.com/rapid-security-response/ "Managing Rapid Security Response on Apple Devices | www.intuneirl.com"
[11]: https://web.archive.org/web/20240321201614/https://onsitegroup.co.za/rapid-security-response/ "Rapid security response - Onsite | onsitegroup.co.za"
[12]: https://web.archive.org/web/20240321201623/https://support.apple.com/en-us/102657 "About Rapid Security Responses for iOS, iPadOS, and macOS - Apple Support | support.apple.com"
docs:
# References for CriticalUpdateInstall
- https://derflounder.wordpress.com/2014/12/24/managing-os-xs-automatic-security-updates/
- https://developer.apple.com/documentation/devicemanagement/softwareupdate
# References for softwareupdate --background-critical
- https://managingosx.wordpress.com/2013/04/30/undocumented-options/
code: |-
# For OS X Yosemite and newer (>= 10.10)
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate 'CriticalUpdateInstall' -bool false

File diff suppressed because it is too large Load Diff

View File

@@ -128,8 +128,3 @@
$calculated-width-in-em: calc(#{$estimated-width-per-character-in-em} * #{$value-in-ch});
#{$property}: $calculated-width-in-em;
}
@mixin base-font-style {
font-family: $font-family-main;
font-size: $font-size-absolute-normal;
}

View File

@@ -21,7 +21,9 @@ $base-spacing: 1em;
body {
background: $color-background;
@include base-font-style;
font-family: $font-family-main;
font-size: $font-size-absolute-normal;
@include apply-uniform-spacing($base-spacing: $base-spacing)
}

View File

@@ -0,0 +1,90 @@
<template>
<div class="card__expander">
<div class="card__expander__close-button">
<FlatButton
icon="xmark"
@click="collapse()"
/>
</div>
<div class="card__expander__content">
<ScriptsTree
:category-id="categoryId"
:has-top-padding="false"
/>
</div>
</div>
</template>
<script lang="ts">
import {
defineComponent,
} from 'vue';
import FlatButton from '@/presentation/components/Shared/FlatButton.vue';
import ScriptsTree from '@/presentation/components/Scripts/View/Tree/ScriptsTree.vue';
export default defineComponent({
components: {
ScriptsTree,
FlatButton,
},
props: {
categoryId: {
type: Number,
required: true,
},
},
emits: {
/* eslint-disable @typescript-eslint/no-unused-vars */
onCollapse: () => true,
/* eslint-enable @typescript-eslint/no-unused-vars */
},
setup(_, { emit }) {
function collapse() {
emit('onCollapse');
}
return {
collapse,
};
},
});
</script>
<style scoped lang="scss">
@use "@/presentation/assets/styles/main" as *;
$expanded-margin-top : 30px;
.card__expander {
transition: all 0.2s ease-in-out;
position: relative;
background-color: $color-primary-darker;
color: $color-on-primary;
display: flex;
align-items: center;
flex-direction: column;
margin-top: $expanded-margin-top;
.card__expander__content {
display: flex;
justify-content: center;
word-break: break-word;
max-width: 100%; // Prevents horizontal expansion of inner content (e.g., when a code block is shown)
width: 100%; // Expands the container to fill available horizontal space, enabling alignment of child items.
}
.card__expander__close-button {
font-size: $font-size-absolute-large;
align-self: flex-end;
margin-right: 0.25em;
@include clickable;
color: $color-primary-light;
@include hover-or-touch {
color: $color-primary;
}
}
}
</style>

View File

@@ -0,0 +1,24 @@
<template>
<div class="arrow-container">
<div class="arrow" />
</div>
</template>
<style scoped lang="scss">
@use "@/presentation/assets/styles/main" as *;
$arrow-size : 15px;
.arrow-container {
position: relative;
.arrow {
position: absolute;
left: calc(50% - $arrow-size * 1.5);
top: calc(1.5 * $arrow-size);
border: solid $color-primary-darker;
border-width: 0 $arrow-size $arrow-size 0;
padding: $arrow-size;
transform: rotate(-135deg);
}
}
</style>

View File

@@ -19,6 +19,7 @@
v-for="categoryId of categoryIds"
:key="categoryId"
class="card"
:total-cards-per-row="cardsPerRow"
:class="{
'small-screen': width <= 500,
'medium-screen': width > 500 && width < 750,
@@ -62,6 +63,19 @@ export default defineComponent({
);
const activeCategoryId = ref<number | undefined>(undefined);
const cardsPerRow = computed<number>(() => {
if (width.value === undefined) {
throw new Error('Unknown width, total cards should not be calculated');
}
if (width.value <= 500) {
return 1;
}
if (width.value < 750) {
return 2;
}
return 3;
});
function onSelected(categoryId: number, isExpanded: boolean) {
activeCategoryId.value = isExpanded ? categoryId : undefined;
}
@@ -108,6 +122,7 @@ export default defineComponent({
width,
categoryIds,
activeCategoryId,
cardsPerRow,
onSelected,
};
},

View File

@@ -29,20 +29,15 @@
:category-id="categoryId"
/>
</div>
<div class="card__expander" @click.stop>
<div class="card__expander__close-button">
<FlatButton
icon="xmark"
@click="collapse()"
/>
</div>
<div class="card__expander__content">
<ScriptsTree
:category-id="categoryId"
:has-top-padding="false"
/>
</div>
</div>
<CardExpansionPanelArrow v-show="isExpanded" />
<ExpandCollapseTransition>
<CardExpansionPanel
v-show="isExpanded"
:category-id="categoryId"
@on-collapse="collapse"
@click.stop
/>
</ExpandCollapseTransition>
</div>
</template>
@@ -51,24 +46,30 @@ import {
defineComponent, computed, shallowRef,
} from 'vue';
import AppIcon from '@/presentation/components/Shared/Icon/AppIcon.vue';
import FlatButton from '@/presentation/components/Shared/FlatButton.vue';
import ExpandCollapseTransition from '@/presentation/components/Shared/ExpandCollapse/ExpandCollapseTransition.vue';
import { injectKey } from '@/presentation/injectionSymbols';
import ScriptsTree from '@/presentation/components/Scripts/View/Tree/ScriptsTree.vue';
import { sleep } from '@/infrastructure/Threading/AsyncSleep';
import CardSelectionIndicator from './CardSelectionIndicator.vue';
import CardExpansionPanel from './CardExpansionPanel.vue';
import CardExpansionPanelArrow from './CardExpansionPanelArrow.vue';
export default defineComponent({
components: {
ScriptsTree,
AppIcon,
CardSelectionIndicator,
FlatButton,
CardExpansionPanel,
ExpandCollapseTransition,
CardExpansionPanelArrow,
},
props: {
categoryId: {
type: Number,
required: true,
},
totalCardsPerRow: {
type: Number,
required: true,
},
activeCategoryId: {
type: Number,
default: undefined,
@@ -94,6 +95,14 @@ export default defineComponent({
},
});
const cardWidth = computed<string>(() => {
const totalTimesGapIsUsedInRow = props.totalCardsPerRow - 1;
const totalGapWidthInRow = `calc(${totalTimesGapIsUsedInRow} * 15px)`; // TODO: 15px is hardcoded, $card-gap variable should be used
const availableRowWidthForCards = `calc(100% - (${totalGapWidthInRow}))`;
const availableWidthPerCard = `calc((${availableRowWidthForCards}) / ${totalTimesGapIsUsedInRow})`;
return availableWidthPerCard;
});
const cardElement = shallowRef<HTMLElement>();
const cardTitle = computed<string>(() => {
@@ -118,6 +127,7 @@ export default defineComponent({
cardTitle,
isExpanded,
cardElement,
cardWidth,
collapse,
};
},
@@ -131,11 +141,22 @@ export default defineComponent({
$card-inner-padding : 30px;
$arrow-size : 15px;
$expanded-margin-top : 30px;
$card-horizontal-gap : $card-gap;
.expansion__arrow {
position: relative;
.expansion__arrow__inner {
position: absolute;
left: calc(50% - $arrow-size * 1.5);
top: calc(1.5 * $arrow-size);
border: solid $color-primary-darker;
border-width: 0 $arrow-size $arrow-size 0;
padding: $arrow-size;
transform: rotate(-135deg);
}
}
.card {
transition: all 0.2s ease-in-out;
width: v-bind(cardWidth);
&__inner {
padding-top: $card-inner-padding;
padding-right: $card-inner-padding;
@@ -160,9 +181,6 @@ $card-horizontal-gap : $card-gap;
color: $color-on-secondary;
transform: scale(1.05);
}
&:after {
transition: all 0.3s ease-in-out;
}
.card__inner__title {
display: flex;
flex-direction: column;
@@ -184,73 +202,12 @@ $card-horizontal-gap : $card-gap;
font-size: $font-size-absolute-normal;
}
}
.card__expander {
transition: all 0.2s ease-in-out;
position: relative;
background-color: $color-primary-darker;
color: $color-on-primary;
display: flex;
align-items: center;
flex-direction: column;
.card__expander__content {
display: flex;
justify-content: center;
word-break: break-word;
max-width: 100%; // Prevents horizontal expansion of inner content (e.g., when a code block is shown)
width: 100%; // Expands the container to fill available horizontal space, enabling alignment of child items.
}
.card__expander__close-button {
font-size: $font-size-absolute-large;
align-self: flex-end;
margin-right: 0.25em;
@include clickable;
color: $color-primary-light;
@include hover-or-touch {
color: $color-primary;
}
}
}
&.is-collapsed {
.card__inner {
&:after {
content: "";
opacity: 0;
}
}
.card__expander {
max-height: 0;
min-height: 0;
overflow: hidden;
opacity: 0;
}
}
&.is-expanded {
.card__inner {
height: auto;
background-color: $color-secondary;
color: $color-on-secondary;
&:after { // arrow
content: "";
display: block;
position: absolute;
bottom: calc(-1 * #{$expanded-margin-top});
left: calc(50% - #{$arrow-size});
border-left: #{$arrow-size} solid transparent;
border-right: #{$arrow-size} solid transparent;
border-bottom: #{$arrow-size} solid $color-primary-darker;
}
}
.card__expander {
min-height: 200px;
margin-top: $expanded-margin-top;
opacity: 1;
}
@include hover-or-touch {
@@ -277,26 +234,26 @@ $card-horizontal-gap : $card-gap;
}
}
@mixin adaptive-card($cards-in-row) {
&.card {
.card {
$total-times-gap-is-used-in-row: $cards-in-row - 1;
$total-gap-width-in-row: $total-times-gap-is-used-in-row * $card-horizontal-gap;
$available-row-width-for-cards: calc(100% - #{$total-gap-width-in-row});
$available-width-per-card: calc(#{$available-row-width-for-cards} / #{$cards-in-row});
width:$available-width-per-card;
.card__expander {
$all-cards-width: 100% * $cards-in-row;
$additional-padding-width: $card-horizontal-gap * ($cards-in-row - 1);
width: calc(#{$all-cards-width} + #{$additional-padding-width});
}
@for $nth-card from 2 through $cards-in-row { // From second card to rest
&:nth-of-type(#{$cards-in-row}n+#{$nth-card}) {
.card__expander {
$card-left: -100% * ($nth-card - 1);
$additional-space: $card-horizontal-gap * ($nth-card - 1);
margin-left: calc(#{$card-left} - #{$additional-space});
}
}
}
// .card__expander {
// $all-cards-width: 100% * $cards-in-row;
// $additional-padding-width: $card-horizontal-gap * ($cards-in-row - 1);
// width: calc(#{$all-cards-width} + #{$additional-padding-width});
// }
// @for $nth-card from 2 through $cards-in-row { // From second card to rest
// &:nth-of-type(#{$cards-in-row}n+#{$nth-card}) {
// .card__expander {
// $card-left: -100% * ($nth-card - 1);
// $additional-space: $card-horizontal-gap * ($nth-card - 1);
// margin-left: calc(#{$card-left} - #{$additional-space});
// }
// }
// }
// Ensure new line after last row
$card-after-last: $cards-in-row + 1;
&:nth-of-type(#{$cards-in-row}n+#{$card-after-last}) {
@@ -304,8 +261,4 @@ $card-horizontal-gap : $card-gap;
}
}
}
.big-screen { @include adaptive-card(3); }
.medium-screen { @include adaptive-card(2); }
.small-screen { @include adaptive-card(1); }
</style>

View File

@@ -220,9 +220,7 @@ $color-tooltip-background: $color-primary-darkest;
color: $color-on-primary;
border-radius: 16px;
padding: 12px 10px;
// Explicitly set font styling for tooltips to prevent inconsistent appearances due to style inheritance from trigger elements.
@include base-font-style;
font-size: $font-size-absolute-normal;
/*
This margin creates a visual buffer between the tooltip and the edges of the document.

View File

@@ -13,4 +13,4 @@ export const RENDERER_URL = process.env.ELECTRON_RENDERER_URL;
export const RENDERER_HTML_PATH = join('file://', __dirname, '../renderer/index.html');
export const PRELOADER_SCRIPT_PATH = join(__dirname, '../preload/index.mjs');
export const PRELOADER_SCRIPT_PATH = join(__dirname, '../preload/index.cjs');

View File

@@ -1,20 +1,18 @@
import { app, dialog } from 'electron/main';
import { autoUpdater, type UpdateInfo } from 'electron-updater';
import { ElectronLogger } from '@/infrastructure/Log/ElectronLogger';
import { UpdateProgressBar } from './UpdateProgressBar';
import { getAutoUpdater } from './ElectronAutoUpdaterFactory';
import type { AppUpdater, UpdateInfo } from 'electron-updater';
import type { ProgressInfo } from 'electron-builder';
export async function handleAutoUpdate() {
const autoUpdater = getAutoUpdater();
if (await askDownloadAndInstall() === DownloadDialogResult.NotNow) {
return;
}
startHandlingUpdateProgress(autoUpdater);
startHandlingUpdateProgress();
await autoUpdater.downloadUpdate();
}
function startHandlingUpdateProgress(autoUpdater: AppUpdater) {
function startHandlingUpdateProgress() {
const progressBar = new UpdateProgressBar();
progressBar.showIndeterminateState();
autoUpdater.on('error', (e) => {
@@ -31,11 +29,11 @@ function startHandlingUpdateProgress(autoUpdater: AppUpdater) {
autoUpdater.on('update-downloaded', async (info: UpdateInfo) => {
ElectronLogger.info('@update-downloaded@\n', info);
progressBar.close();
await handleUpdateDownloaded(autoUpdater);
await handleUpdateDownloaded();
});
}
async function handleUpdateDownloaded(autoUpdater: AppUpdater) {
async function handleUpdateDownloaded() {
if (await askRestartAndInstall() === InstallDialogResult.NotNow) {
return;
}

View File

@@ -1,8 +0,0 @@
import electronUpdater, { type AppUpdater } from 'electron-updater';
export function getAutoUpdater(): AppUpdater {
// Using destructuring to access autoUpdater due to the CommonJS module of 'electron-updater'.
// It is a workaround for ESM compatibility issues, see https://github.com/electron-userland/electron-builder/issues/7976.
const { autoUpdater } = electronUpdater;
return autoUpdater;
}

View File

@@ -1,16 +1,13 @@
import { autoUpdater, type UpdateInfo } from 'electron-updater';
import { ElectronLogger } from '@/infrastructure/Log/ElectronLogger';
import { requiresManualUpdate, startManualUpdateProcess } from './ManualUpdater/ManualUpdateCoordinator';
import { handleAutoUpdate } from './AutomaticUpdateCoordinator';
import { getAutoUpdater } from './ElectronAutoUpdaterFactory';
import type { UpdateInfo } from 'electron-updater';
interface Updater {
checkForUpdates(): Promise<void>;
}
export function setupAutoUpdater(): Updater {
const autoUpdater = getAutoUpdater();
autoUpdater.logger = ElectronLogger;
// Auto-downloads are disabled to allow separate handling of 'check' and 'download' actions,

View File

@@ -1,7 +1,6 @@
import {
describe, it, beforeAll, afterAll,
} from 'vitest';
import { formatAssertionMessage } from '@tests/shared/FormatAssertionMessage';
import { main } from './check-desktop-runtime-errors/main';
import { COMMAND_LINE_FLAGS, CommandLineFlag } from './check-desktop-runtime-errors/cli-args';
@@ -15,10 +14,7 @@ describe('desktop runtime error checks', () => {
() => main(),
);
// assert
expect(exitCode).to.equal(0, formatAssertionMessage([
`Test failed with exit code ${exitCode}; expected 0.`,
'Examine preceding logs to identify errors.',
]));
expect(exitCode).to.equal(0);
}, {
timeout: 60 /* minutes */ * 60000,
});

View File

@@ -10,10 +10,7 @@ export async function getUrlStatusesInParallel(
): Promise<UrlStatus[]> {
// urls = ['https://privacy.sexy']; // Comment out this line to use a hardcoded URL for testing.
const uniqueUrls = Array.from(new Set(urls));
const defaultedDomainOptions: Required<DomainOptions> = {
...DefaultDomainOptions,
...options?.domainOptions,
};
const defaultedDomainOptions = { ...DefaultDomainOptions, ...options?.domainOptions };
console.log('Batch request options applied:', defaultedDomainOptions);
const results = await request(uniqueUrls, defaultedDomainOptions, options);
return results;

View File

@@ -1,4 +1,3 @@
import { indentText } from '@tests/shared/Text';
import { fetchWithTimeout } from './FetchWithTimeout';
import { getDomainFromUrl } from './UrlDomainProcessing';
@@ -8,12 +7,8 @@ export function fetchFollow(
fetchOptions?: Partial<RequestInit>,
followOptions?: Partial<FollowOptions>,
): Promise<Response> {
const defaultedFollowOptions: Required<FollowOptions> = {
...DefaultFollowOptions,
...followOptions,
};
console.log(indentText(`Follow options: ${JSON.stringify(defaultedFollowOptions)}`));
if (!followRedirects(defaultedFollowOptions)) {
const defaultedFollowOptions = { ...DefaultFollowOptions, ...followOptions };
if (followRedirects(defaultedFollowOptions)) {
return fetchWithTimeout(url, timeoutInMs, fetchOptions);
}
fetchOptions = { ...fetchOptions, redirect: 'manual' /* handled manually */, mode: 'cors' };
@@ -27,6 +22,8 @@ export function fetchFollow(
);
}
// "cors" | "navigate" | "no-cors" | "same-origin";
export interface FollowOptions {
readonly followRedirects?: boolean;
readonly maximumRedirectFollowDepth?: number;
@@ -101,11 +98,11 @@ class CookieStorage {
}
function followRedirects(options: FollowOptions): boolean {
if (options.followRedirects !== true) {
if (!options.followRedirects) {
return false;
}
if (options.maximumRedirectFollowDepth === undefined || options.maximumRedirectFollowDepth <= 0) {
throw new Error('Invalid followRedirects configuration: maximumRedirectFollowDepth must be a positive integer');
if (options.maximumRedirectFollowDepth === 0) {
return false;
}
return true;
}

View File

@@ -100,10 +100,3 @@ console.log(`Status code: ${status.code}`);
- **`enableCookies`** (*boolean*), default: `true`
- Enables cookie storage to facilitate seamless navigation through login or other authentication challenges.
- 💡 Helps to over-come sign-in challenges with callbacks.
- **`forceHttpGetForUrlPatterns`** (*array*), default: `[]`
- Specifies URL patterns that should always use an HTTP GET request instead of the default HTTP HEAD.
- This is useful for websites that do not respond to HEAD requests, such as those behind certain CDN or web application firewalls.
- Provide patterns as regular expressions (`RegExp`), allowing them to match any part of a URL.
- Examples:
- To match any URL starting with "https://example.com/api": `/^https:\/\/example\.com\/api/`
- To match any domain ending with "cloudflare.com": `/^https:\/\/.*\.cloudflare\.com\//`

View File

@@ -24,7 +24,6 @@ export interface RequestOptions {
readonly additionalHeadersUrlIgnore?: string[];
readonly requestTimeoutInMs: number;
readonly randomizeTlsFingerprint: boolean;
readonly forceHttpGetForUrlPatterns: RegExp[];
}
const DefaultOptions: Required<RequestOptions> = {
@@ -33,7 +32,6 @@ const DefaultOptions: Required<RequestOptions> = {
additionalHeadersUrlIgnore: [],
requestTimeoutInMs: 60 /* seconds */ * 1000,
randomizeTlsFingerprint: true,
forceHttpGetForUrlPatterns: [],
};
function fetchUrlStatusWithRetry(
@@ -43,11 +41,7 @@ function fetchUrlStatusWithRetry(
): Promise<UrlStatus> {
const fetchOptions = getFetchOptions(url, requestOptions);
return retryWithExponentialBackOff(async () => {
console.log(`🚀 Initiating request for URL: ${url}`);
console.log(indentText([
`HTTP method: ${fetchOptions.method}`,
`Request options: ${JSON.stringify(requestOptions)}`,
].join('\n')));
console.log(`Initiating request for URL: ${url}`);
let result: UrlStatus;
try {
const response = await fetchFollow(
@@ -62,8 +56,7 @@ function fetchUrlStatusWithRetry(
url,
error: [
'Error:', indentText(JSON.stringify(err, null, '\t') || err.toString()),
'Fetch options:', indentText(JSON.stringify(fetchOptions, null, '\t')),
'Request options:', indentText(JSON.stringify(requestOptions, null, '\t')),
'Options:', indentText(JSON.stringify(fetchOptions, null, '\t')),
'TLS:', indentText(getTlsContextInfo()),
].join('\n'),
};
@@ -78,7 +71,7 @@ function getFetchOptions(url: string, options: Required<RequestOptions>): Reques
? {}
: options.additionalHeaders;
return {
method: getHttpMethod(url, options),
method: 'GET', // Fetch only headers without the full response body for better speed
headers: {
...getDefaultHeaders(url),
...additionalHeaders,
@@ -87,14 +80,6 @@ function getFetchOptions(url: string, options: Required<RequestOptions>): Reques
};
}
function getHttpMethod(url: string, options: Required<RequestOptions>): 'HEAD' | 'GET' {
if (options.forceHttpGetForUrlPatterns.some((pattern) => url.match(pattern))) {
return 'GET';
}
// By default fetch only headers without the full response body for better speed
return 'HEAD';
}
function getDefaultHeaders(url: string): Record<string, string> {
return {
// Needed for websites that filter out non-browser user agents.

View File

@@ -23,12 +23,12 @@ import { indentText } from '@tests/shared/Text';
export function randomizeTlsFingerprint() {
tls.DEFAULT_CIPHERS = getShuffledCiphers().join(':');
console.log(indentText(
`TLS context:\n${indentText([
console.log(
[
'Original ciphers:', indentText(constants.defaultCipherList),
'Current ciphers:', indentText(getTlsContextInfo()),
].join('\n'))}`,
));
'Current context', indentText(getTlsContextInfo()),
].join('\n'),
);
}
export function getTlsContextInfo(): string {

View File

@@ -73,12 +73,10 @@ function formatUrlStatusReport(deadUrlStatuses: readonly UrlStatus[]): string {
function extractUrls(textWithInlineCode: string): string[] {
/*
Matches URLs:
- Excludes inline code blocks as they may contain URLs not intended for user interaction
and not guaranteed to support expected HTTP methods, leading to false-negatives.
- Supports URLs containing parentheses, avoiding matches within code that might not represent
actual links.
Matches all URLs.
Inline code blocks contain URLs not intended for user interaction and not
guaranteed to support expected HTTP methods, leading to false-negatives.
*/
const nonCodeBlockUrlRegex = /(?<!`)(https?:\/\/[^\s`"<>()]+(?:\([^\s`"<>()]*\))?[^\s`"<>()]*)/g;
const nonCodeBlockUrlRegex = /(?<!`)(https?:\/\/[^\s`"<>()]+)/g;
return textWithInlineCode.match(nonCodeBlockUrlRegex) || [];
}

View File

@@ -2,7 +2,6 @@ import { describe, it, expect } from 'vitest';
import { FunctionCallArgumentCollection } from '@/application/Parser/Script/Compiler/Function/Call/Argument/FunctionCallArgumentCollection';
import { FunctionCallArgumentStub } from '@tests/unit/shared/Stubs/FunctionCallArgumentStub';
import { itEachAbsentStringValue } from '@tests/unit/shared/TestCases/AbsentTests';
import type { IFunctionCallArgument } from '@/application/Parser/Script/Compiler/Function/Call/Argument/IFunctionCallArgument';
describe('FunctionCallArgumentCollection', () => {
describe('addArgument', () => {
@@ -21,25 +20,21 @@ describe('FunctionCallArgumentCollection', () => {
});
});
describe('getAllParameterNames', () => {
describe('returns as expected', () => {
it('returns as expected', () => {
// arrange
const testCases: ReadonlyArray<{
readonly description: string;
readonly args: readonly IFunctionCallArgument[];
readonly expectedParameterNames: string[];
}> = [{
description: 'no args',
const testCases = [{
name: 'no args',
args: [],
expectedParameterNames: [],
expected: [],
}, {
description: 'with some args',
name: 'with some args',
args: [
new FunctionCallArgumentStub().withParameterName('a-param-name'),
new FunctionCallArgumentStub().withParameterName('b-param-name')],
expectedParameterNames: ['a-param-name', 'b-param-name'],
expected: ['a-param-name', 'b-param-name'],
}];
for (const testCase of testCases) {
it(testCase.description, () => {
it(testCase.name, () => {
const sut = new FunctionCallArgumentCollection();
// act
for (const arg of testCase.args) {
@@ -47,7 +42,7 @@ describe('FunctionCallArgumentCollection', () => {
}
const actual = sut.getAllParameterNames();
// assert
expect(actual).to.deep.equal(testCase.expectedParameterNames);
expect(actual).to.equal(testCase.expected);
});
}
});

View File

@@ -25,7 +25,7 @@ describe('SharedFunction', () => {
// assert
expect(sut.name).equal(expected);
});
describe('throws when absent', () => {
it('throws when absent', () => {
itEachAbsentStringValue((absentValue) => {
// arrange
const expectedError = 'missing function name';

View File

@@ -4,7 +4,6 @@ import { InjectionKeys } from '@/presentation/injectionSymbols';
import { provideDependencies, type VueDependencyInjectionApi } from '@/presentation/bootstrapping/DependencyProvider';
import { ApplicationContextStub } from '@tests/unit/shared/Stubs/ApplicationContextStub';
import { itIsSingleton } from '@tests/unit/shared/TestCases/SingletonTests';
import type { IApplicationContext } from '@/application/Context/IApplicationContext';
describe('DependencyProvider', () => {
describe('provideDependencies', () => {
@@ -75,25 +74,25 @@ function createSingletonTests() {
const registeredObject = api.inject(injectionKey);
expect(registeredObject).to.be.instanceOf(Object);
});
describe('should return the same instance for singleton dependency', () => {
// arrange
const singletonContext = new ApplicationContextStub();
const api = new VueDependencyInjectionApiStub();
new ProvideDependenciesBuilder()
.withContext(singletonContext)
.withApi(api)
.provideDependencies();
// act
const getRegisteredInstance = () => api.inject(injectionKey);
// assert
it('should return the same instance for singleton dependency', () => {
itIsSingleton({
getter: getRegisteredInstance,
getter: () => {
// arrange
const api = new VueDependencyInjectionApiStub();
// act
new ProvideDependenciesBuilder()
.withApi(api)
.provideDependencies();
// expect
const registeredObject = api.inject(injectionKey);
return registeredObject;
},
});
});
};
}
class ProvideDependenciesBuilder {
private context: IApplicationContext = new ApplicationContextStub();
private context = new ApplicationContextStub();
private api: VueDependencyInjectionApi = new VueDependencyInjectionApiStub();
@@ -102,11 +101,6 @@ class ProvideDependenciesBuilder {
return this;
}
public withContext(context: IApplicationContext): this {
this.context = context;
return this;
}
public provideDependencies() {
return provideDependencies(this.context, this.api);
}

View File

@@ -10,7 +10,7 @@ import type { TreeInputNodeData } from '@/presentation/components/Scripts/View/T
describe('TreeNodeInitializerAndUpdater', () => {
describe('updateRootNodes', () => {
describe('should throw an error if no data is provided', () => {
it('should throw an error if no data is provided', () => {
itEachAbsentCollectionValue<TreeInputNodeData>((absentValue) => {
// arrange
const expectedError = 'missing data';

View File

@@ -13,7 +13,7 @@ import { ScriptDiagnosticsCollectorStub } from '../../../shared/Stubs/ScriptDiag
describe('IpcRegistration', () => {
describe('registerAllIpcChannels', () => {
describe('registers all defined IPC channels', () => {
it('registers all defined IPC channels', () => {
Object.entries(IpcChannelDefinitions).forEach(([key, expectedChannel]) => {
it(key, () => {
// arrange

View File

@@ -55,7 +55,7 @@ function getPathAliasesFromTsConfig(): ViteAliasDefinitions {
}
function getElectronProcessSpecificModuleAliases(): ViteAliasDefinitions {
// Workaround for Vite not being able to build tests with scoped Electron module imports.
// Workaround for scoped Electron module imports due to https://github.com/alex8088/electron-vite/issues/372
const electronProcessScopedModuleAliases = [
'electron/main',
'electron/renderer',