Compare commits
333 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d11a674a3c | ||
|
|
31f70913a2 | ||
|
|
bd23faa28f | ||
|
|
5b1fbe1e2f | ||
|
|
96265b75de | ||
|
|
17298f0b2c | ||
|
|
61b475fa8d | ||
|
|
455084c17b | ||
|
|
c3c5b897f3 | ||
|
|
a1871a2982 | ||
|
|
87de017afd | ||
|
|
5a2c263af3 | ||
|
|
ddd2e704db | ||
|
|
9b5e0b0591 | ||
|
|
9b6636e21a | ||
|
|
a8358b8e7a | ||
|
|
5f091bb6ab | ||
|
|
17b334aaad | ||
|
|
c65209e6a9 | ||
|
|
d2518b11a7 | ||
|
|
70cdf3865a | ||
|
|
7c02ffb6c9 | ||
|
|
f2d9881382 | ||
|
|
d7761ab30e | ||
|
|
bf83c58982 | ||
|
|
2e082932c9 | ||
|
|
2f90cac52a | ||
|
|
20a0071c0d | ||
|
|
a40f83d6b6 | ||
|
|
0db8cc4206 | ||
|
|
97ddc027cb | ||
|
|
82c43ba2e3 | ||
|
|
799fb091b8 | ||
|
|
5ead1a087d | ||
|
|
64631a4552 | ||
|
|
f47cb04860 | ||
|
|
504fa056d7 | ||
|
|
739287ac71 | ||
|
|
ab8bce7686 | ||
|
|
e6152fa76f | ||
|
|
a8031d18d5 | ||
|
|
9aa8166891 | ||
|
|
236a0f6c82 | ||
|
|
2492f2d814 | ||
|
|
410bcd8244 | ||
|
|
b08a6b5cec | ||
|
|
37ad26a082 | ||
|
|
0696ed8396 | ||
|
|
9942df16c8 | ||
|
|
20b7d283b0 | ||
|
|
f39ee76c0c | ||
|
|
4b2390736a | ||
|
|
c8cb7a5c28 | ||
|
|
5217b0b758 | ||
|
|
ddf417a16a | ||
|
|
2f0321f315 | ||
|
|
4d7ff7edc5 | ||
|
|
862914b06e | ||
|
|
6c3c2e6709 | ||
|
|
c92dc1e253 | ||
|
|
e73c0ad1bf | ||
|
|
6a89c6224b | ||
|
|
dcccb61781 | ||
|
|
c0c475ff56 | ||
|
|
6dc768817f | ||
|
|
439cd303ff | ||
|
|
ec0c972d34 | ||
|
|
2a08855e5d | ||
|
|
1c6b3057ea | ||
|
|
ea5f9ec27d | ||
|
|
f2935e4008 | ||
|
|
487001af48 | ||
|
|
71e70e50c5 | ||
|
|
0a857aa09e | ||
|
|
b976b92031 | ||
|
|
db62ed7f3a | ||
|
|
36f0805590 | ||
|
|
49600c5f37 | ||
|
|
eb9ac35a92 | ||
|
|
77148980e0 | ||
|
|
b3d2e82025 | ||
|
|
b25b8cc805 | ||
|
|
8141a01ef7 | ||
|
|
a2f10857e2 | ||
|
|
aea04e5f7c | ||
|
|
60c80611ea | ||
|
|
b1ed3ce55f | ||
|
|
040ed2701c | ||
|
|
00d8e551db | ||
|
|
3e9c99f5f8 | ||
|
|
02bdc4cf04 | ||
|
|
5c43965f0b | ||
|
|
b2376ecc30 | ||
|
|
aeaa6deeb4 | ||
|
|
448e378dc4 | ||
|
|
ac2249f256 | ||
|
|
05932c5a36 | ||
|
|
6f46cdb4ed | ||
|
|
5f527a00cf | ||
|
|
1935db1019 | ||
|
|
1f515e7be5 | ||
|
|
1a5f92021f | ||
|
|
f3c7413f52 | ||
|
|
646db90585 | ||
|
|
1f8a0cf9ab | ||
|
|
bd41af466f | ||
|
|
970221b996 | ||
|
|
15004ff1f1 | ||
|
|
65226f3984 | ||
|
|
b0a7d0b53b | ||
|
|
ee43fd92a0 | ||
|
|
cf39e6d254 | ||
|
|
1260eea690 | ||
|
|
45a3669443 | ||
|
|
c9b91f6d8f | ||
|
|
9a6b903b92 | ||
|
|
7661575573 | ||
|
|
f1abd7682f | ||
|
|
575636e6b7 | ||
|
|
daa997b21b | ||
|
|
5934b17283 | ||
|
|
d7de420d5c | ||
|
|
df273f7f63 | ||
|
|
67b2d1c11c | ||
|
|
15353d0e25 | ||
|
|
f1e21babbf | ||
|
|
34b8822ac8 | ||
|
|
73e0520de7 | ||
|
|
fbc3b109b9 | ||
|
|
229c13a195 | ||
|
|
d7f9ef1cbe | ||
|
|
7930bef48c | ||
|
|
8b0e47da38 | ||
|
|
2316e3fb68 | ||
|
|
4015e2ccd8 | ||
|
|
cf907d029a | ||
|
|
79a6c8b2ef | ||
|
|
c318bd301a | ||
|
|
86a2b2fda0 | ||
|
|
8a8b7319d5 | ||
|
|
2428de23ee | ||
|
|
7ec889e759 | ||
|
|
9d009c40dd | ||
|
|
663d63bde0 | ||
|
|
6b83dcbf8f | ||
|
|
72e925fb6f | ||
|
|
c299e95bc6 | ||
|
|
2e40605d59 | ||
|
|
3455a2ca6c | ||
|
|
6fe858d86a | ||
|
|
7cc161c828 | ||
|
|
e14bf2bfa0 | ||
|
|
34672414c3 | ||
|
|
f7557bcc0f | ||
|
|
e4b6cdfb18 | ||
|
|
8cd3352017 | ||
|
|
c4ec6a1445 | ||
|
|
b3117c27f2 | ||
|
|
54ba4dbb0b | ||
|
|
a744415eb2 | ||
|
|
55f936fee9 | ||
|
|
d9e44e2574 | ||
|
|
52d4313156 | ||
|
|
c2b531e968 | ||
|
|
ab7d617886 | ||
|
|
b247b12c3f | ||
|
|
c26bc209eb | ||
|
|
ad1872e7cd | ||
|
|
29c7704e0b | ||
|
|
e41e40c5bf | ||
|
|
31e08d231d | ||
|
|
45b8dd972b | ||
|
|
4e72673373 | ||
|
|
92c3dd9232 | ||
|
|
2c5ab3ea7d | ||
|
|
ffa279f3df | ||
|
|
89dddfbb23 | ||
|
|
cfedcd724c | ||
|
|
fd28eaad06 | ||
|
|
8ce06facbd | ||
|
|
1a9db31c77 | ||
|
|
ac70b063b8 | ||
|
|
d0019c2c9b | ||
|
|
4c68408f1e | ||
|
|
1072505219 | ||
|
|
07fc555324 | ||
|
|
50fb29038a | ||
|
|
3785c623f8 | ||
|
|
14be3017c5 | ||
|
|
978bab0b81 | ||
|
|
d9d7f62d81 | ||
|
|
11e0613165 | ||
|
|
77c3d2bbb8 | ||
|
|
784a67afff | ||
|
|
19a092dd31 | ||
|
|
4c2f74949b | ||
|
|
a3fc3782ef | ||
|
|
cdc93f032a | ||
|
|
7dd15ed064 | ||
|
|
d169434157 | ||
|
|
6efed72bf2 | ||
|
|
15db311801 | ||
|
|
82d509129b | ||
|
|
939d838e35 | ||
|
|
6de4ce58c4 | ||
|
|
ee66196d9a | ||
|
|
3c13a9e837 | ||
|
|
22b23a9ece | ||
|
|
4ae385b7fc | ||
|
|
d9abc7f0b2 | ||
|
|
1f19b2528a | ||
|
|
1f11c39773 | ||
|
|
b6ccb5927a | ||
|
|
1d465ee318 | ||
|
|
3ab48b1cf5 | ||
|
|
de4ac978bd | ||
|
|
8df5faf4ef | ||
|
|
99a2035fdb | ||
|
|
a0d61728ea | ||
|
|
312bf6102c | ||
|
|
f4885b6f1c | ||
|
|
ca63a0979e | ||
|
|
1f266c3353 | ||
|
|
c7b2a70312 | ||
|
|
255133af4d | ||
|
|
db74531cd4 | ||
|
|
f36d8bfc78 | ||
|
|
3b31ace726 | ||
|
|
6badfef9da | ||
|
|
8c38dd73d8 | ||
|
|
b8682a852a | ||
|
|
8c17929151 | ||
|
|
bb92c9ec28 | ||
|
|
b4aacea2a3 | ||
|
|
8bbe6ebf75 | ||
|
|
a23d28f2cf | ||
|
|
f51e8859ee | ||
|
|
d235dee955 | ||
|
|
2afef4ea3d | ||
|
|
f709d6a566 | ||
|
|
532915b95d | ||
|
|
456e40bedf | ||
|
|
018b7e270f | ||
|
|
f8b8b4c97a | ||
|
|
978d7d0863 | ||
|
|
594a14d6ca | ||
|
|
c628aa9aef | ||
|
|
3060ebf79c | ||
|
|
1a34c7374b | ||
|
|
c262681011 | ||
|
|
f8ba5c46e4 | ||
|
|
b789250cb8 | ||
|
|
5df458739d | ||
|
|
d6fa9a2a03 | ||
|
|
ec15af01dd | ||
|
|
7073336f81 | ||
|
|
3d3380f27e | ||
|
|
c69998c7cb | ||
|
|
1663bfeac7 | ||
|
|
afc3bfb3b8 | ||
|
|
b6bfc25727 | ||
|
|
7fac0fe79f | ||
|
|
5967347b80 | ||
|
|
855a445c1a | ||
|
|
1cc12195a3 | ||
|
|
66d4d39d5b | ||
|
|
a5dbe66fc1 | ||
|
|
4c8be45e28 | ||
|
|
6049a2b834 | ||
|
|
831c014f97 | ||
|
|
5c15a7a64a | ||
|
|
e43992b278 | ||
|
|
5963d2bac5 | ||
|
|
45816a2bcc | ||
|
|
60a5a2aa40 | ||
|
|
04b9b59e14 | ||
|
|
4ff4b52202 | ||
|
|
73c426844a | ||
|
|
25ce236a77 | ||
|
|
9b20175545 | ||
|
|
92a7118d1c | ||
|
|
a9f9e90443 | ||
|
|
31d2067f07 | ||
|
|
dd7e1416b4 | ||
|
|
1d5225de07 | ||
|
|
9c063d59de | ||
|
|
57028987f1 | ||
|
|
9e722ddfb3 | ||
|
|
646a8e0b9f | ||
|
|
f27a2871d7 | ||
|
|
909c44d72a | ||
|
|
53cf595e17 | ||
|
|
2c4eb78c3f | ||
|
|
d7a1325c0b | ||
|
|
30efbcc621 | ||
|
|
628c16eb95 | ||
|
|
d8552c62ff | ||
|
|
df84083536 | ||
|
|
461a4f122b | ||
|
|
c937af8ee7 | ||
|
|
636d4279c8 | ||
|
|
019b838925 | ||
|
|
0fc18459cd | ||
|
|
583c5660d6 | ||
|
|
52d5713a99 | ||
|
|
b34a66f270 | ||
|
|
eed996f608 | ||
|
|
b96c5d0557 | ||
|
|
aab8f21a8d | ||
|
|
c668a97950 | ||
|
|
bb98d20637 | ||
|
|
e2ab124fb7 | ||
|
|
0d2efe5b05 | ||
|
|
156a6554ef | ||
|
|
4a91e8ccd8 | ||
|
|
997be7113f | ||
|
|
3e3bc07576 | ||
|
|
691f989682 | ||
|
|
226074c534 | ||
|
|
97b7e03233 | ||
|
|
749a140eb8 | ||
|
|
4739a4ac40 | ||
|
|
4800340b9b | ||
|
|
074734242b | ||
|
|
802b36bdd8 | ||
|
|
0c39a06be5 | ||
|
|
e63ac4ae67 | ||
|
|
edd076fade | ||
|
|
0ce354ea09 | ||
|
|
19813b6917 | ||
|
|
97a7747933 | ||
|
|
92f1a36bcb | ||
|
|
31364bdfec |
9
.dockerignore
Normal file
@@ -0,0 +1,9 @@
|
||||
node_modules
|
||||
dist
|
||||
dist_electron
|
||||
.vs
|
||||
.vscode
|
||||
.github
|
||||
.git
|
||||
docs
|
||||
docker
|
||||
7
.editorconfig
Normal file
@@ -0,0 +1,7 @@
|
||||
[*.{js,jsx,ts,tsx,vue}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
max_line_length = 100
|
||||
115
.eslintrc.js
Normal file
@@ -0,0 +1,115 @@
|
||||
const { rules: baseStyleRules } = require('eslint-config-airbnb-base/rules/style');
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
extends: [
|
||||
// Vue specific rules, eslint-plugin-vue
|
||||
// Added by Vue CLI
|
||||
'plugin:vue/essential',
|
||||
|
||||
// Extends eslint-config-airbnb
|
||||
// Added by Vue CLI
|
||||
// Here until https://github.com/vuejs/eslint-config-airbnb/issues/23 is done
|
||||
'@vue/airbnb',
|
||||
|
||||
// Extends @typescript-eslint/recommended
|
||||
// Uses the recommended rules from the @typescript-eslint/eslint-plugin
|
||||
// Added by Vue CLI
|
||||
'@vue/typescript/recommended',
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
},
|
||||
rules: {
|
||||
...getOwnRules(),
|
||||
...getTurnedOffBrokenRules(),
|
||||
...getOpinionatedRuleOverrides(),
|
||||
...getTodoRules(),
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: [
|
||||
'**/__tests__/*.{j,t}s?(x)',
|
||||
'**/tests/unit/**/*.spec.{j,t}s?(x)',
|
||||
],
|
||||
env: {
|
||||
mocha: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/tests/**/*.{j,t}s?(x)'],
|
||||
rules: {
|
||||
'no-console': 'off',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
function getOwnRules() {
|
||||
return {
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
'linebreak-style': ['error', 'unix'], // This is also enforced in .editorconfig and .gitattributes files
|
||||
'import/order': [ // Enforce strict import order taking account into aliases
|
||||
'error',
|
||||
{
|
||||
groups: [ // Enforce more strict order than AirBnb
|
||||
'builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
|
||||
pathGroups: [ // Fix manually configured paths being incorrectly grouped as "external"
|
||||
'@/**', // @/..
|
||||
'@tests/**', // @tests/.. (not matching anything after @** because there can be third parties as well)
|
||||
'js-yaml-loader!@/**', // E.g. js-yaml-loader!@/..
|
||||
].map((pattern) => ({ pattern, group: 'internal' })),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function getTodoRules() { // Should be worked on separate future commits
|
||||
return {
|
||||
'import/no-extraneous-dependencies': 'off',
|
||||
// Requires webpack configuration change with import '..yaml' files.
|
||||
'import/no-webpack-loader-syntax': 'off',
|
||||
'import/extensions': 'off',
|
||||
'import/no-unresolved': 'off',
|
||||
// Accessibility improvements:
|
||||
'vuejs-accessibility/form-control-has-label': 'off',
|
||||
'vuejs-accessibility/click-events-have-key-events': 'off',
|
||||
'vuejs-accessibility/anchor-has-content': 'off',
|
||||
'vuejs-accessibility/accessible-emoji': 'off',
|
||||
};
|
||||
}
|
||||
|
||||
function getTurnedOffBrokenRules() {
|
||||
return {
|
||||
// Broken in TypeScript
|
||||
'no-useless-constructor': 'off', // Cannot interpret TypeScript constructors
|
||||
'no-shadow': 'off', // Fails with TypeScript enums
|
||||
};
|
||||
}
|
||||
|
||||
function getOpinionatedRuleOverrides() {
|
||||
return {
|
||||
// https://erkinekici.com/articles/linting-trap#no-use-before-define
|
||||
'no-use-before-define': 'off',
|
||||
// https://erkinekici.com/articles/linting-trap#arrow-body-style
|
||||
'arrow-body-style': 'off',
|
||||
// https://erkinekici.com/articles/linting-trap#no-plusplus
|
||||
'no-plusplus': 'off',
|
||||
// https://erkinekici.com/articles/linting-trap#no-param-reassign
|
||||
'no-param-reassign': 'off',
|
||||
// https://erkinekici.com/articles/linting-trap#class-methods-use-this
|
||||
'class-methods-use-this': 'off',
|
||||
// https://erkinekici.com/articles/linting-trap#importprefer-default-export
|
||||
'import/prefer-default-export': 'off',
|
||||
// https://erkinekici.com/articles/linting-trap#disallowing-for-of
|
||||
// Original: https://github.com/airbnb/javascript/blob/d8cb404da74c302506f91e5928f30cc75109e74d/packages/eslint-config-airbnb-base/rules/style.js#L333-L351
|
||||
'no-restricted-syntax': [
|
||||
baseStyleRules['no-restricted-syntax'][0],
|
||||
...baseStyleRules['no-restricted-syntax'].slice(1).filter((rule) => rule.selector !== 'ForOfStatement'),
|
||||
],
|
||||
};
|
||||
}
|
||||
6
.gitattributes
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
# Prevent Git from auto-converting to CRLF on Windows, and convert to LF on checkin.
|
||||
# * : All files
|
||||
# text=auto : If Git decides content it text, it converts CRLF to LF on checkin.
|
||||
# eol=lf : forces Git to normalize line endings to LF on checkin and prevents conversion
|
||||
# to CRLF when the file is checked out.
|
||||
* text=auto eol=lf
|
||||
56
.github/ISSUE_TEMPLATE/1-bug-report-scripts.md
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
---
|
||||
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 you can find it using "Start button" > "Settings" > "System" > "About".
|
||||
On macOS you can find it using "Apple menu (top left corner)" > "About This Mac".
|
||||
-->
|
||||
|
||||
### 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.
|
||||
-->
|
||||
55
.github/ISSUE_TEMPLATE/2-bug-report-generic.md
vendored
Normal 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.
|
||||
-->
|
||||
36
.github/ISSUE_TEMPLATE/3-feature-request.md
vendored
Normal 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.
|
||||
-->
|
||||
73
.github/ISSUE_TEMPLATE/4-new-script-suggestion.md
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
---
|
||||
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?
|
||||
Either "Windows" or "macOS".
|
||||
-->
|
||||
|
||||
### 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:
|
||||
- macOS: bash (sh)
|
||||
- Windows: PowerShell (ps1) or batchfile
|
||||
- 💡 Prioritize the one that's simpler, batchfile 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.
|
||||
-->
|
||||
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: true
|
||||
91
.github/workflows/build-and-deploy.yaml
vendored
@@ -1,91 +0,0 @@
|
||||
name: Build & deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
-
|
||||
name: "Prepare: Checkout"
|
||||
uses: actions/checkout@v1
|
||||
-
|
||||
name: "Prepare: Create AWS user profile"
|
||||
run: >-
|
||||
bash "aws/scripts/configure/create-user-profile.sh" \
|
||||
--profile user \
|
||||
--access-key-id ${{secrets.AWS_DEPLOYMENT_USER_ACCESS_KEY_ID}} \
|
||||
--secret-access-key ${{secrets.AWS_DEPLOYMENT_USER_SECRET_ACCESS_KEY}} \
|
||||
--region us-east-1
|
||||
-
|
||||
name: "Infrastructure: Deploy IAM stack"
|
||||
run: >-
|
||||
bash "aws/scripts/deploy/deploy-stack.sh" \
|
||||
--template-file aws/iam-stack.yaml \
|
||||
--stack-name privacysexy-iam-stack \
|
||||
--capabilities CAPABILITY_IAM \
|
||||
--region us-east-1 --role-arn ${{secrets.AWS_IAM_STACK_DEPLOYMENT_ROLE_ARN}} \
|
||||
--profile user --session ${{github.actor}}-${{github.event_name}}-${{github.sha}}
|
||||
-
|
||||
name: "Infrastructure: Deploy certificate stack"
|
||||
run: >-
|
||||
bash "aws/scripts/deploy/deploy-stack.sh" \
|
||||
--template-file aws/certificate-stack.yaml \
|
||||
--stack-name privacysexy-certificate-stack \
|
||||
--region us-east-1 \
|
||||
--role-arn ${{secrets.AWS_CERTIFICATE_STACK_DEPLOYMENT_ROLE_ARN}} \
|
||||
--profile user --session ${{github.actor}}-${{github.event_name}}-${{github.sha}}
|
||||
-
|
||||
name: "Infrastructure: Deploy DNS stack"
|
||||
run: >-
|
||||
bash "aws/scripts/deploy/deploy-stack.sh" \
|
||||
--template-file aws/dns-stack.yaml \
|
||||
--stack-name privacysexy-dns-stack \
|
||||
--region us-east-1 \
|
||||
--role-arn ${{secrets.AWS_DNS_STACK_DEPLOYMENT_ROLE_ARN}} \
|
||||
--profile user --session ${{github.actor}}-${{github.event_name}}-${{github.sha}}
|
||||
-
|
||||
name: "Infrastructure: Deploy web stack"
|
||||
run: >-
|
||||
bash "aws/scripts/deploy/deploy-stack.sh" \
|
||||
--template-file aws/web-stack.yaml \
|
||||
--stack-name privacysexy-web-stack \
|
||||
--region us-east-1 \
|
||||
--role-arn ${{secrets.AWS_WEB_STACK_DEPLOYMENT_ROLE_ARN}} \
|
||||
--profile user --session ${{github.actor}}-${{github.event_name}}-${{github.sha}}
|
||||
-
|
||||
name: "App: Setup node"
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '11.x'
|
||||
-
|
||||
name: "App: Install dependencies"
|
||||
run: npm install
|
||||
-
|
||||
name: "App: Run tests"
|
||||
run: npm run test:unit
|
||||
-
|
||||
name: "App: Build"
|
||||
run: npm run build
|
||||
-
|
||||
name: "App: Deploy to S3"
|
||||
run: >-
|
||||
bash "aws/scripts/deploy/deploy-to-s3.sh" \
|
||||
--folder dist \
|
||||
--web-stack-name privacysexy-web-stack --web-stack-s3-name-output-name S3BucketName \
|
||||
--storage-class ONEZONE_IA \
|
||||
--role-arn ${{secrets.AWS_S3_SITE_DEPLOYMENT_ROLE_ARN}} \
|
||||
--region us-east-1 \
|
||||
--profile user --session ${{github.actor}}-${{github.event_name}}-${{github.sha}}
|
||||
-
|
||||
name: "App: Invalidate CloudFront cache"
|
||||
run: >-
|
||||
bash "aws/scripts/deploy/invalidate-cloudfront-cache.sh" \
|
||||
--paths "/*" \
|
||||
--web-stack-name privacysexy-web-stack --web-stack-cloudfront-arn-output-name CloudFrontDistributionArn \
|
||||
--role-arn ${{secrets.AWS_CLOUDFRONT_SITE_DEPLOYMENT_ROLE_ARN}} \
|
||||
--region us-east-1 \
|
||||
--profile user --session ${{github.actor}}-${{github.event_name}}-${{github.sha}}
|
||||
59
.github/workflows/checks.build.yaml
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
name: build-checks
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build-web:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ macos, ubuntu, windows ]
|
||||
mode: [ development, test, production ]
|
||||
fail-fast: false # Allows to see results from other combinations
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
-
|
||||
name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 15.x
|
||||
-
|
||||
name: Install dependencies
|
||||
run: npm ci
|
||||
-
|
||||
name: Build
|
||||
run: npm run build -- --mode ${{ matrix.mode }}
|
||||
|
||||
# A new job is used due to environments/modes different from Vue CLI, https://github.com/nklayman/vue-cli-plugin-electron-builder/issues/1626
|
||||
build-desktop:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ macos, ubuntu, windows ]
|
||||
mode: [ development, production ] # "test" is not supported https://github.com/nklayman/vue-cli-plugin-electron-builder/issues/1627
|
||||
fail-fast: false # Allows to see results from other combinations
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
-
|
||||
name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 15.x
|
||||
-
|
||||
name: Install dependencies
|
||||
run: npm ci
|
||||
-
|
||||
name: Install cross-env
|
||||
# Used to set NODE_ENV due to https://github.com/nklayman/vue-cli-plugin-electron-builder/issues/1626
|
||||
run: npm install --global cross-env
|
||||
-
|
||||
name: Build
|
||||
run: |-
|
||||
cross-env-shell NODE_ENV=${{ matrix.mode }}
|
||||
npm run electron:build -- --publish never --mode ${{ matrix.mode }}
|
||||
28
.github/workflows/checks.quality.yaml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: quality-checks
|
||||
|
||||
on: [ push, pull_request ]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
lint-command:
|
||||
- npm run lint:eslint
|
||||
- npm run lint:yaml
|
||||
- npm run lint:md
|
||||
- npm run lint:md:relative-urls
|
||||
- npm run lint:md:consistency
|
||||
os: [ macos, ubuntu, windows ]
|
||||
fail-fast: false # Still interested to see results from other combinations
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 15.x
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Lint
|
||||
run: ${{ matrix.lint-command }}
|
||||
24
.github/workflows/checks.security.yaml
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
name: security-checks
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
paths: [ '/package.json', '/package-lock.json' ] # Allow PRs to be green if they do not introduce dependency change
|
||||
schedule:
|
||||
- cron: '0 0 * * 0' # at 00:00 on every Sunday
|
||||
|
||||
jobs:
|
||||
npm-audit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
-
|
||||
name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 15.x
|
||||
-
|
||||
name: NPM audit
|
||||
run: exit "$(npm audit)" # Since node 15.x, it does not fail with error if we don't explicitly exit
|
||||
34
.github/workflows/release.desktop.yaml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
name: release-desktop
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [created] # will be triggered when a NON-draft release is created and published.
|
||||
|
||||
jobs:
|
||||
publish-desktop-app:
|
||||
name: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos, ubuntu, windows]
|
||||
fail-fast: false # So publish runs for other OSes if one fails
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: master # otherwise it defaults to the version tag missing bump commit
|
||||
fetch-depth: 0 # fetch all history
|
||||
- name: Checkout to bump commit
|
||||
run: git checkout "$(git rev-list "${{ github.event.release.tag_name }}"..master | tail -1)"
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 15.x
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Run unit tests
|
||||
run: npm run test:unit
|
||||
- name: Publish desktop app
|
||||
run: npm run electron:build -- -p always # https://nklayman.github.io/vue-cli-plugin-electron-builder/guide/recipes.html#upload-release-to-github
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
EP_GH_IGNORE_TIME: true # Otherwise publishing fails if GitHub release is more than 2 hours old https://github.com/electron-userland/electron-builder/issues/2074
|
||||
17
.github/workflows/release.git.yaml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
name: release-git
|
||||
|
||||
on:
|
||||
push: # Ensure a new release is created for each new tag
|
||||
tags:
|
||||
- '[0-9]+.[0-9]+.[0-9]+'
|
||||
|
||||
jobs:
|
||||
bump-version-and-release:
|
||||
if: github.event.base_ref == 'refs/heads/master'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: undergroundwires/bump-everywhere@master
|
||||
with:
|
||||
user: undergroundwires-bot
|
||||
release-token: ${{ secrets.BUMP_GITHUB_PAT }} # Does not trigger release pipeline if we use default token: https://github.community/t5/GitHub-Actions/Github-Action-trigger-on-release-not-working-if-releases-was/td-p/34559
|
||||
# GitHub does not inject secrets if pipeline runs from fork or a fork is merged to main repo.
|
||||
117
.github/workflows/release.site.yaml
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
name: release-site
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [created] # will be triggered when a NON-draft release is created and published.
|
||||
|
||||
jobs:
|
||||
aws-deploy: # see: https://github.com/undergroundwires/aws-static-site-with-cd
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: "Infrastructure: Checkout"
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: aws
|
||||
repository: undergroundwires/aws-static-site-with-cd
|
||||
-
|
||||
name: "Infrastructure: Create AWS user profile & session name"
|
||||
run: >-
|
||||
bash "scripts/configure/create-user-profile.sh" \
|
||||
--profile user \
|
||||
--access-key-id ${{secrets.AWS_DEPLOYMENT_USER_ACCESS_KEY_ID}} \
|
||||
--secret-access-key ${{secrets.AWS_DEPLOYMENT_USER_SECRET_ACCESS_KEY}} \
|
||||
--region us-east-1 \
|
||||
&& \
|
||||
echo "SESSION_NAME=${{github.actor}}-${{github.event_name}}-$(echo ${{github.sha}} | cut -c1-8)" >> $GITHUB_ENV
|
||||
working-directory: aws
|
||||
-
|
||||
name: "Infrastructure: Deploy IAM stack"
|
||||
run: >-
|
||||
bash "scripts/deploy/deploy-stack.sh" \
|
||||
--template-file stacks/iam-stack.yaml \
|
||||
--stack-name privacysexy-iam-stack \
|
||||
--capabilities CAPABILITY_IAM \
|
||||
--parameter-overrides "WebStackName=privacysexy-web-stack DnsStackName=privacysexy-dns-stack \
|
||||
CertificateStackName=privacysexy-cert-stack RootDomainName=privacy.sexy" \
|
||||
--region us-east-1 --role-arn ${{secrets.AWS_IAM_STACK_DEPLOYMENT_ROLE_ARN}} \
|
||||
--profile user --session ${{ env.SESSION_NAME }}
|
||||
working-directory: aws
|
||||
-
|
||||
name: "Infrastructure: Deploy DNS stack"
|
||||
run: >-
|
||||
bash "scripts/deploy/deploy-stack.sh" \
|
||||
--template-file stacks/dns-stack.yaml \
|
||||
--stack-name privacysexy-dns-stack \
|
||||
--parameter-overrides "RootDomainName=privacy.sexy" \
|
||||
--region us-east-1 \
|
||||
--role-arn ${{secrets.AWS_DNS_STACK_DEPLOYMENT_ROLE_ARN}} \
|
||||
--profile user --session ${{ env.SESSION_NAME }}
|
||||
working-directory: aws
|
||||
-
|
||||
name: "Infrastructure: Deploy certificate stack"
|
||||
run: >-
|
||||
bash "scripts/deploy/deploy-stack.sh" \
|
||||
--template-file stacks/certificate-stack.yaml \
|
||||
--stack-name privacysexy-cert-stack \
|
||||
--capabilities CAPABILITY_IAM \
|
||||
--parameter-overrides "IamStackName=privacysexy-iam-stack RootDomainName=privacy.sexy DnsStackName=privacysexy-dns-stack" \
|
||||
--region us-east-1 \
|
||||
--role-arn ${{secrets.AWS_CERTIFICATE_STACK_DEPLOYMENT_ROLE_ARN}} \
|
||||
--profile user --session ${{ env.SESSION_NAME }}
|
||||
working-directory: aws
|
||||
-
|
||||
name: "Infrastructure: Deploy web stack"
|
||||
run: >-
|
||||
bash "scripts/deploy/deploy-stack.sh" \
|
||||
--template-file stacks/web-stack.yaml \
|
||||
--stack-name privacysexy-web-stack \
|
||||
--parameter-overrides "CertificateStackName=privacysexy-cert-stack DnsStackName=privacysexy-dns-stack \
|
||||
RootDomainName=privacy.sexy UseDeepLinks=true" \
|
||||
--capabilities CAPABILITY_IAM \
|
||||
--region us-east-1 \
|
||||
--role-arn ${{secrets.AWS_WEB_STACK_DEPLOYMENT_ROLE_ARN}} \
|
||||
--profile user --session ${{ env.SESSION_NAME }}
|
||||
working-directory: aws
|
||||
-
|
||||
name: "App: Checkout"
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: site
|
||||
ref: master # otherwise we don't get version bump commit
|
||||
-
|
||||
name: "App: Setup node"
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 15.x
|
||||
-
|
||||
name: "App: Install dependencies"
|
||||
run: npm ci
|
||||
working-directory: site
|
||||
-
|
||||
name: "App: Run unit tests"
|
||||
run: npm run test:unit
|
||||
working-directory: site
|
||||
-
|
||||
name: "App: Build"
|
||||
run: npm run build
|
||||
working-directory: site
|
||||
-
|
||||
name: "App: Deploy to S3"
|
||||
run: >-
|
||||
bash "aws/scripts/deploy/deploy-to-s3.sh" \
|
||||
--folder site/dist \
|
||||
--web-stack-name privacysexy-web-stack --web-stack-s3-name-output-name S3BucketName \
|
||||
--storage-class ONEZONE_IA \
|
||||
--role-arn ${{secrets.AWS_S3_SITE_DEPLOYMENT_ROLE_ARN}} \
|
||||
--region us-east-1 \
|
||||
--profile user --session ${{ env.SESSION_NAME }}
|
||||
-
|
||||
name: "App: Invalidate CloudFront cache"
|
||||
run: >-
|
||||
bash "aws/scripts/deploy/invalidate-cloudfront-cache.sh" \
|
||||
--paths "/*" \
|
||||
--web-stack-name privacysexy-web-stack --web-stack-cloudfront-arn-output-name CloudFrontDistributionArn \
|
||||
--role-arn ${{secrets.AWS_CLOUDFRONT_SITE_DEPLOYMENT_ROLE_ARN}} \
|
||||
--region us-east-1 \
|
||||
--profile user --session ${{ env.SESSION_NAME }}
|
||||
26
.github/workflows/run-tests.yaml
vendored
@@ -1,26 +0,0 @@
|
||||
name: Run tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
- '!master'
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
-
|
||||
name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '11.x'
|
||||
-
|
||||
name: Install dependencies
|
||||
run: npm install
|
||||
-
|
||||
name: Run tests
|
||||
run: npm run test:unit
|
||||
28
.github/workflows/tests.e2e.yaml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: e2e-tests
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
run-tests:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos, ubuntu, windows]
|
||||
fail-fast: false # So it still runs on other OSes if one of them fails
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
-
|
||||
name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 15.x
|
||||
-
|
||||
name: Install dependencies
|
||||
run: npm ci
|
||||
-
|
||||
name: Run e2e tests
|
||||
run: npm run test:e2e -- --headless
|
||||
30
.github/workflows/tests.integration.yaml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: integration-tests
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule: # To get notified about problems from third party dependencies
|
||||
- cron: '0 0 * * 0' # at 00:00 on every Sunday
|
||||
|
||||
jobs:
|
||||
run-tests:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos, ubuntu, windows]
|
||||
fail-fast: false # So it still runs on other OSes if one of them fails
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
-
|
||||
name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 15.x
|
||||
-
|
||||
name: Install dependencies
|
||||
run: npm ci
|
||||
-
|
||||
name: Run integration tests
|
||||
run: npm run test:integration
|
||||
28
.github/workflows/tests.unit.yaml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: unit-tests
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
run-tests:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos, ubuntu, windows]
|
||||
fail-fast: false # So it still runs on other OSes if one of them fails
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
-
|
||||
name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 15.x
|
||||
-
|
||||
name: Install dependencies
|
||||
run: npm ci
|
||||
-
|
||||
name: Run unit tests
|
||||
run: npm run test:unit
|
||||
9
.gitignore
vendored
@@ -1,4 +1,9 @@
|
||||
node_modules
|
||||
/dist
|
||||
dist/
|
||||
.vs
|
||||
.vscode
|
||||
.vscode
|
||||
#Electron-builder output
|
||||
/dist_electron
|
||||
# Cypress
|
||||
/tests/e2e/screenshots
|
||||
/tests/e2e/videos
|
||||
|
||||
4
.markdownlint.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"default": true,
|
||||
"MD013": false
|
||||
}
|
||||
516
CHANGELOG.md
@@ -1,40 +1,502 @@
|
||||
# Changelog
|
||||
|
||||
- All notable changes to this project will be documented in this file.
|
||||
## 0.11.2 (2021-12-03)
|
||||
|
||||
## [Unreleased]
|
||||
* Fix Windows TrustedInstaller session errors | [20a0071](https://github.com/undergroundwires/privacy.sexy/commit/20a0071c0d3d769a8f31218abdbfc4cafa25c6ff)
|
||||
* Improve tests for `UserSelection` | [2f90cac](https://github.com/undergroundwires/privacy.sexy/commit/2f90cac52ab9e57615aeec41f9daa842bce770a5)
|
||||
* Fix disabling/enabling Defender on Windows #104 | [2e08293](https://github.com/undergroundwires/privacy.sexy/commit/2e082932c952b0849ab2b8709ff0c75293b88e95)
|
||||
* Refactor Saas naming, structure and modules | [bf83c58](https://github.com/undergroundwires/privacy.sexy/commit/bf83c58982ffa178facc6d35e50c7f1eac7ff236)
|
||||
* Fix Defender features errors in Windows #104 | [d7761ab](https://github.com/undergroundwires/privacy.sexy/commit/d7761ab30e7f1e10a2919c196804d67511d6163a)
|
||||
* Fix unintendedly inlined Windows scripts | [f2d9881](https://github.com/undergroundwires/privacy.sexy/commit/f2d988138257ff184884e4adc83c39e3bc247e9b)
|
||||
* Fix Defender error due to non-english Windows #104 | [7c02ffb](https://github.com/undergroundwires/privacy.sexy/commit/7c02ffb6c95382b94f0b05e6f259cc418ec91c93)
|
||||
* Improve and unify disabling of Windows services | [70cdf38](https://github.com/undergroundwires/privacy.sexy/commit/70cdf3865a0de3214fc9e26fbdada4b0cb413c46)
|
||||
* Improve Windows defender docs and errors #104 | [d2518b1](https://github.com/undergroundwires/privacy.sexy/commit/d2518b11a7774ec58b9b46a691e2f013855bf0f9)
|
||||
* Unrecommend and complete Windows Push Notif. #101 | [c65209e](https://github.com/undergroundwires/privacy.sexy/commit/c65209e6a99230f15ace8955e8d5a6f3333d146b)
|
||||
|
||||
## [0.4.0] - 2020-01-11
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.11.1...0.11.2)
|
||||
|
||||
- Added search
|
||||
- Some styling improvements
|
||||
- Better organization of scripts + more scripts
|
||||
## 0.11.1 (2021-11-04)
|
||||
|
||||
## [0.3.0] - 2020-01-09
|
||||
* Update dependencies | [64631a4](https://github.com/undergroundwires/privacy.sexy/commit/64631a4552fad7f7b06286aba8d3ca2d731f9342)
|
||||
* Fix, document, unrecommend Windows browser cleanup | [5ead1a0](https://github.com/undergroundwires/privacy.sexy/commit/5ead1a087d91948890bc4ae6fea176123f18c285)
|
||||
* Fix failing URL status checking integration tests | [799fb09](https://github.com/undergroundwires/privacy.sexy/commit/799fb091b8eb06c70ac0c67f2ef5385dce73501f)
|
||||
* Refactor to remove "Async" function name suffix | [82c43ba](https://github.com/undergroundwires/privacy.sexy/commit/82c43ba2e37fb6e7f62ccd9bec8c5f48575f0613)
|
||||
* Fix dead URLs and use forks as GitHub references | [97ddc02](https://github.com/undergroundwires/privacy.sexy/commit/97ddc027cb5395a74991cabc1d8c875ee945636d)
|
||||
* Fix website not loading on Safari | [0db8cc4](https://github.com/undergroundwires/privacy.sexy/commit/0db8cc420655e01cbbed57c4658489b761a15899)
|
||||
|
||||
- Added support for grouping
|
||||
- Added some meta tags
|
||||
- Added "Disable NVIDIA telemetry" script
|
||||
- Added legacy browser compatibility for fonts & changed main font
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.11.0...0.11.1)
|
||||
|
||||
## [0.2.0] - 2020-01-06
|
||||
## 0.11.0 (2021-10-21)
|
||||
|
||||
- Fixed typo in generated code.
|
||||
- Better URL validation for documentation links in `application.yaml`.
|
||||
- Slightly faster parsing of `application.yaml`
|
||||
- Styled no JS error that's shown when JavaScript is disabled.
|
||||
- The default selection is now *None* & instruction text is shown in code box when nothing is selected.
|
||||
- Added hyphen lines when rendering of long function names
|
||||
- Changed subtitle: added version as footer instead.
|
||||
* Change "grouping" to "view" | [c0c475f](https://github.com/undergroundwires/privacy.sexy/commit/c0c475ff564b23a4dabcc03ac2909207a8eb61ce)
|
||||
* Tighten parameter substitution tolerance | [dcccb61](https://github.com/undergroundwires/privacy.sexy/commit/dcccb617813625c224a28242c5b965bb4cd6f189)
|
||||
* Add optionality for parameters | [6a89c62](https://github.com/undergroundwires/privacy.sexy/commit/6a89c6224bdef5eb96980471f3b3935b9351b197)
|
||||
* Do not collapse cards on links and code area #88 | [e73c0ad](https://github.com/undergroundwires/privacy.sexy/commit/e73c0ad1bf922b1dd3360fc5aafc3434951fa63c)
|
||||
* Add scripts to disable, hide and opt-out from Siri | [c92dc1e](https://github.com/undergroundwires/privacy.sexy/commit/c92dc1e25387c65a3a41ca64d2a23cf8131b4c86)
|
||||
* Improve macOS scripts for cleaning OS logs | [6c3c2e6](https://github.com/undergroundwires/privacy.sexy/commit/6c3c2e6709ec84f8e0411f19c024bab2c7e5753b)
|
||||
* Add "with" expression for templating #53 | [862914b](https://github.com/undergroundwires/privacy.sexy/commit/862914b06ea9ef74c4b58a9a4164a10a38273638)
|
||||
* Add support for pipes in templates #53 | [4d7ff7e](https://github.com/undergroundwires/privacy.sexy/commit/4d7ff7edc5a96cc0d99d3c1ca4fdf9bbdace3fd2)
|
||||
* Bump node environment to 15.x | [2f0321f](https://github.com/undergroundwires/privacy.sexy/commit/2f0321f315ac0da8c713dd50e37032f1de194942)
|
||||
* Add new UX for optionally downloading updates | [ddf417a](https://github.com/undergroundwires/privacy.sexy/commit/ddf417a16a79551b43576befab0541ea08487969)
|
||||
* Add pipes to write pretty PowerShell #53 | [5217b0b](https://github.com/undergroundwires/privacy.sexy/commit/5217b0b7587ccfe509ba8adc3a7748b9bae14d7a)
|
||||
* Improve alignment, padding/margin issues on UI | [c8cb7a5](https://github.com/undergroundwires/privacy.sexy/commit/c8cb7a5c28420557319606da82f56b011e88f470)
|
||||
* Support disabling per-user services in Windows #16 | [4b23907](https://github.com/undergroundwires/privacy.sexy/commit/4b2390736ac1f9de2d5176b7b07da0e827112f9a)
|
||||
* Add script to remove Meet Now icon in Windows | [f39ee76](https://github.com/undergroundwires/privacy.sexy/commit/f39ee76c0cda95f54502b19d5c49390fd0f12b5e)
|
||||
* Add support for more depth in function calls | [20b7d28](https://github.com/undergroundwires/privacy.sexy/commit/20b7d283b02dd751dfbde18ef1fe334c6bf76e2b)
|
||||
* Increase default screen width on desktop app | [9942df1](https://github.com/undergroundwires/privacy.sexy/commit/9942df16c8334ff041fb92f432a3a29e351c88df)
|
||||
* Improve disabling of SmartScreen #74 | [0696ed8](https://github.com/undergroundwires/privacy.sexy/commit/0696ed8396e298a358bec17adb91c9145dd90418)
|
||||
* Remove integration tests from deployments #90 | [37ad26a](https://github.com/undergroundwires/privacy.sexy/commit/37ad26a082851c02497c36e7fce40555b9480e11)
|
||||
* Use a consistent color system | [b08a6b5](https://github.com/undergroundwires/privacy.sexy/commit/b08a6b5cecf4a53023053695292146edbd24b960)
|
||||
* Add semi-automatic update support for macOS | [410bcd8](https://github.com/undergroundwires/privacy.sexy/commit/410bcd82445097c29c9fcf0eabf7af9ebcb93c1e)
|
||||
* Add more ways to disable and clean Defender #74 | [2492f2d](https://github.com/undergroundwires/privacy.sexy/commit/2492f2d8141b3abdf590ccad59680b1f50ecb59e)
|
||||
* Add privacy over security scripts for macOS #83 | [236a0f6](https://github.com/undergroundwires/privacy.sexy/commit/236a0f6c8241294fc397194cd1b20bdeccbbb50b)
|
||||
* Change PowerShell double quotes escape | [9aa8166](https://github.com/undergroundwires/privacy.sexy/commit/9aa816689146ee6cd86d8262112677c38651c6bd)
|
||||
* Change theme colors | [a8031d1](https://github.com/undergroundwires/privacy.sexy/commit/a8031d18d520dd3b0567f7b8cfe2dcd694b65073)
|
||||
* Improve security hardening for macOS | [e6152fa](https://github.com/undergroundwires/privacy.sexy/commit/e6152fa76f5e7d23b0f79d5dd98713daaecbff90)
|
||||
* Support disabling of protected services #74 | [ab8bce7](https://github.com/undergroundwires/privacy.sexy/commit/ab8bce768650a10677f0a13b3a9fae93c83802ff)
|
||||
* Fix minor issues with Defender scripts | [739287a](https://github.com/undergroundwires/privacy.sexy/commit/739287ac71b3f8b04348fc101f1fa06f2d7d86a2)
|
||||
* Update screenshot | [504fa05](https://github.com/undergroundwires/privacy.sexy/commit/504fa056d7d8b17fc20afd398f9a557495fca7e8)
|
||||
|
||||
## [0.1.0] - 2019-12-31
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.10.3...0.11.0)
|
||||
|
||||
- Initial release
|
||||
## 0.10.3 (2021-08-27)
|
||||
|
||||
## All releases
|
||||
* unrecommend VSS and document its breaking behavior | [7714898](https://github.com/undergroundwires/privacy.sexy/commit/77148980e08859f89c15c6604e55b56ce4f74358)
|
||||
* fix incorrect modification of Desktop folder on ThisPC (#71) | [eb9ac35](https://github.com/undergroundwires/privacy.sexy/commit/eb9ac35a923325cc2c9983ef71c0d904337a58f5)
|
||||
* add initial integration tests | [49600c5](https://github.com/undergroundwires/privacy.sexy/commit/49600c5f37ca33c1687885fdf02a71ef7d3e6e8c)
|
||||
* unify usage of sleepAsync and add tests | [36f0805](https://github.com/undergroundwires/privacy.sexy/commit/36f08055909f371fd9cbe3480ea813b963aea22b)
|
||||
* fix broken URLs and automate broken URL checks #70 | [db62ed7](https://github.com/undergroundwires/privacy.sexy/commit/db62ed7f3ac63e9f2d762eb946060595eb9f5626)
|
||||
* fix hiding recent files in quick access | [b976b92](https://github.com/undergroundwires/privacy.sexy/commit/b976b920318dba55b32d39f148fdca4f6be3cce3)
|
||||
* bump dependencies to latest #75, #69 | [0a857aa](https://github.com/undergroundwires/privacy.sexy/commit/0a857aa09ee703d34ad0422bd1731158017a9a58)
|
||||
* Fix NTP configuration before running the service (#72) | [71e70e5](https://github.com/undergroundwires/privacy.sexy/commit/71e70e50c51249bb10f6203414948b325acc2b2a)
|
||||
* Fix typo on main page (#82) | [487001a](https://github.com/undergroundwires/privacy.sexy/commit/487001af485fdbb958615d7b52c09c2e386ddaf2)
|
||||
* Improve issue templates | [f2935e4](https://github.com/undergroundwires/privacy.sexy/commit/f2935e4008f1231ef174f8932290e11715564d20)
|
||||
* Fix infinitely subscribing to state changes | [ea5f9ec](https://github.com/undergroundwires/privacy.sexy/commit/ea5f9ec27df7cec6ac575e23fef18948d2b8e68a)
|
||||
* Fix select options being clickable when disabled | [1c6b305](https://github.com/undergroundwires/privacy.sexy/commit/1c6b3057ea6e45125cadf374f20a905712ccdf3c)
|
||||
* Fix tests for `ParameterSubstitutionParser` | [2a08855](https://github.com/undergroundwires/privacy.sexy/commit/2a08855e5d1bdf74354fd692cbfebd1a48e495ac)
|
||||
* Fix excessive highlighting on hover | [ec0c972](https://github.com/undergroundwires/privacy.sexy/commit/ec0c972d348ffd5897f115d201031b704875b56a)
|
||||
* Fix dead URLs | [439cd30](https://github.com/undergroundwires/privacy.sexy/commit/439cd303ff3db96a53664e5f44fefe12b95c5e6c)
|
||||
|
||||
- [Unreleased] : https://github.com/undergroundwires/privacy.sexy/compare/v0.4.0...HEAD
|
||||
- [v0.4.0] : https://github.com/undergroundwires/privacy.sexy/compare/v0.3.0...v0.4.0
|
||||
- [v0.3.0] : https://github.com/undergroundwires/privacy.sexy/compare/v0.2.0...v0.3.0
|
||||
- [v0.2.0] : https://github.com/undergroundwires/privacy.sexy/compare/v0.1.0...v0.2.0
|
||||
- [v0.1.0] : https://github.com/undergroundwires/privacy.sexy/releases/tag/v0.1.0
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.10.2...0.10.3)
|
||||
|
||||
## 0.10.2 (2021-04-19)
|
||||
|
||||
* in CI/CD, run other tests/check even if one of them fails | [5c43965](https://github.com/undergroundwires/privacy.sexy/commit/5c43965f0bc44f991ada7d3bad68937a80665dc3)
|
||||
* fix desktop initial window size being bigger than current display size on smaller Linux/Windows screens | [02bdc4c](https://github.com/undergroundwires/privacy.sexy/commit/02bdc4cf0426c452f3fc9af52b819ca9b0757290)
|
||||
* refactor extra code, duplicates, complexity | [00d8e55](https://github.com/undergroundwires/privacy.sexy/commit/00d8e551db001247fadfb6f6af7a4c5ce19a9e64)
|
||||
* improve disabling ads and marketing #65 | [040ed27](https://github.com/undergroundwires/privacy.sexy/commit/040ed2701c4a468749901f4c5369b221bc0973c4)
|
||||
* document breaking behavior in script name #64 | [b1ed3ce](https://github.com/undergroundwires/privacy.sexy/commit/b1ed3ce55f2d003cad1ead23e674aa66d4eb5802)
|
||||
* add module alias '@tests/' | [60c8061](https://github.com/undergroundwires/privacy.sexy/commit/60c80611eab227791fabb883caf93418cef5fd00)
|
||||
* document chromium warning for policy changes | [aea04e5](https://github.com/undergroundwires/privacy.sexy/commit/aea04e5f7cd48fbb9b407b68ade75575a6064c82)
|
||||
* fix script revert activating recommendation level | [a2f1085](https://github.com/undergroundwires/privacy.sexy/commit/a2f10857e2a8debb3ce01f79b0dfbe8649ea9a17)
|
||||
* fix typo and dead URL in Windows scripts (#70) | [8141a01](https://github.com/undergroundwires/privacy.sexy/commit/8141a01ef798331b4d82f5ca95f7b18df4f6f912)
|
||||
* fix vue warning for undefined property during render | [b25b8cc](https://github.com/undergroundwires/privacy.sexy/commit/b25b8cc8052655af70b0695c6c3085974d783bb6)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.10.1...0.10.2)
|
||||
|
||||
## 0.10.1 (2021-03-25)
|
||||
|
||||
* refactor script compilation to make it easy to add new expressions #41 #53 | [646db90](https://github.com/undergroundwires/privacy.sexy/commit/646db9058541cebd0af437554de04fdc6bb63a6e)
|
||||
* restructure presentation layer | [f3c7413](https://github.com/undergroundwires/privacy.sexy/commit/f3c7413f529be4a00dba7b0ab23904b48ea13a35)
|
||||
* fix a test where "it" is not used inside "describe" | [1a5f920](https://github.com/undergroundwires/privacy.sexy/commit/1a5f92021f7423cd039f8f5326cd6f99b355c962)
|
||||
* bump dependencies to latest | [1f515e7](https://github.com/undergroundwires/privacy.sexy/commit/1f515e7be525291c960ccb71db05312db6da53f5)
|
||||
* fix throttle function not being able to run with argument(s) | [1935db1](https://github.com/undergroundwires/privacy.sexy/commit/1935db10192051401ab00ca2cd767955d0d3b866)
|
||||
* fix fs module hanging not allowing code to run | [5f527a0](https://github.com/undergroundwires/privacy.sexy/commit/5f527a00cf225d3e74b3f6577d6e2456e919de24)
|
||||
* refactor all modals to use same dialog component | [6f46cdb](https://github.com/undergroundwires/privacy.sexy/commit/6f46cdb4ed49a8941c6c0dde5c5e2a816c06daef)
|
||||
* fix safari cleanup scripts that are not working on modern versions | [05932c5](https://github.com/undergroundwires/privacy.sexy/commit/05932c5a36446d551c5bc811165e3295fbe15e3f)
|
||||
* refactor features to use shared functions #41 | [ac2249f](https://github.com/undergroundwires/privacy.sexy/commit/ac2249f25664827d8a6d2c7ebd659ccf126b0cde)
|
||||
* increase performance by polyfilling ResizeObserver only if required | [448e378](https://github.com/undergroundwires/privacy.sexy/commit/448e378dc4501f9de69af63634c87d0e5060bf52)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.10.0...0.10.1)
|
||||
|
||||
## 0.10.0 (2021-03-02)
|
||||
|
||||
* allow functions to call other functions #53 | [7661575](https://github.com/undergroundwires/privacy.sexy/commit/7661575573c6d3e8f4bc28bfa7a124a764c72ef9)
|
||||
* add option to run script directly in desktop app | [9a6b903](https://github.com/undergroundwires/privacy.sexy/commit/9a6b903b9297802845043fd41115756acd4a145c)
|
||||
* add script to automatically kill devicecensus process | [c9b91f6](https://github.com/undergroundwires/privacy.sexy/commit/c9b91f6d8f9bd16308b6beda119e7154a985b6cf)
|
||||
* refactor disabling application experience and document better | [45a3669](https://github.com/undergroundwires/privacy.sexy/commit/45a3669443d82855a52f60524d341c15f380f9e7)
|
||||
* escape printed characters to prevent command injection #45 | [1260eea](https://github.com/undergroundwires/privacy.sexy/commit/1260eea690e4fa5420e58c9de9f88cc29cb242db)
|
||||
* move code area to right on bigger screens | [cf39e6d](https://github.com/undergroundwires/privacy.sexy/commit/cf39e6d2541ea547f41d9553c380c54c24c58038)
|
||||
* more scripts to disable speech recognition and Cortana | [ee43fd9](https://github.com/undergroundwires/privacy.sexy/commit/ee43fd92a019ebd26c13890f9146c5b5bb56afaf)
|
||||
* add more macos scripts for privacy cleanup | [b0a7d0b](https://github.com/undergroundwires/privacy.sexy/commit/b0a7d0b53b3d8ac144a0241d70c037f460b0c0cc)
|
||||
* add better error messages to setting vscode settings | [65226f3](https://github.com/undergroundwires/privacy.sexy/commit/65226f3984480d0bc7932fd8d76a328f08308850)
|
||||
* remove windows scripts for removing non-bloating system apps #55 | [15004ff](https://github.com/undergroundwires/privacy.sexy/commit/15004ff1f1fb85a1d92e11ef695bcb2f37110610)
|
||||
* remove "preview" disclaimer from macOS | [970221b](https://github.com/undergroundwires/privacy.sexy/commit/970221b996e25fe5b029cbaa78607c9bbc8c3c0e)
|
||||
* update screenshot | [bd41af4](https://github.com/undergroundwires/privacy.sexy/commit/bd41af466fd135f7dc2f171633e4f60d8547c373)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.9.2...0.10.0)
|
||||
|
||||
## 0.9.2 (2021-02-13)
|
||||
|
||||
* do not compile with unused locals vuejs/vetur#1063 | [73e0520](https://github.com/undergroundwires/privacy.sexy/commit/73e0520de70cdbaf0ecdc6e9be5e85f003fcfb79)
|
||||
* fix wrong path for NvTelemtry file in NVIDIA script | [34b8822](https://github.com/undergroundwires/privacy.sexy/commit/34b8822ac821acb47e483e21b57e380551bcf455)
|
||||
* refactor event handling to consume base class for lifecycling | [f1e21ba](https://github.com/undergroundwires/privacy.sexy/commit/f1e21babbfaac21903594a37e30163bfe3338279)
|
||||
* make compiler throw if a function call includes an unexpected parameter | [15353d0](https://github.com/undergroundwires/privacy.sexy/commit/15353d0e2513c89ee4ffd9d9c5e9e83ef69b96b6)
|
||||
* refactor vscode configuration scripts using functions #41 | [67b2d1c](https://github.com/undergroundwires/privacy.sexy/commit/67b2d1c11cd5b131dff93a4437db79d96ed8b3dc)
|
||||
* refactor state handling to make application available independent of the state | [df273f7](https://github.com/undergroundwires/privacy.sexy/commit/df273f7f635ab156ac51a8dfb3fec66c4979f1c4)
|
||||
* add test to ensure correct shared functions are being parsed | [d7de420](https://github.com/undergroundwires/privacy.sexy/commit/d7de420d5c91bd9ce64880cd4a4391ad3a0a5401)
|
||||
* refactor and add tests for NonCollapsingDirective | [5934b17](https://github.com/undergroundwires/privacy.sexy/commit/5934b1728328c3b2ece1597b74dd87477d162175)
|
||||
* add GitHub issue templates | [daa997b](https://github.com/undergroundwires/privacy.sexy/commit/daa997b21b624d133c6f5e4cd6b70214588f9144)
|
||||
* correct the typo in application.md (#60) | [575636e](https://github.com/undergroundwires/privacy.sexy/commit/575636e6b728a2bdd1a9bd72c57bbf2752f10887)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.9.1...0.9.2)
|
||||
|
||||
## 0.9.1 (2021-01-23)
|
||||
|
||||
* in CI/CD, allow publishing to github if release is more than 2 hours old electron-userland/electron-builder#2074 | [cf907d0](https://github.com/undergroundwires/privacy.sexy/commit/cf907d029a6d80682ba78ec887a9c4fab639db51)
|
||||
* in CI/CD, publish packages for other OSes if single one fails | [4015e2c](https://github.com/undergroundwires/privacy.sexy/commit/4015e2ccd8492e0693365b70fbfe3bd0ac7a6ea2)
|
||||
* specify desktop publish targets as defaults (may) change | [2316e3f](https://github.com/undergroundwires/privacy.sexy/commit/2316e3fb6867e5d765eafcf675b77f88bd2a0f52)
|
||||
* fix selection state indicator on cards not showing up | [8b0e47d](https://github.com/undergroundwires/privacy.sexy/commit/8b0e47da38c49cfe2645d7d25970c448ecd200f8)
|
||||
* transpile using babel for legacy browser support | [7930bef](https://github.com/undergroundwires/privacy.sexy/commit/7930bef48c4e9a4fe0823673958ed8377f5ee533)
|
||||
* fix node APIs no longer working on desktop nklayman/vue-cli-plugin-electron-builder#610, nklayman/vue-cli-plugin-electron-builder#742 | [d7f9ef1](https://github.com/undergroundwires/privacy.sexy/commit/d7f9ef1cbebe911aa19f29be8c5fa9360550793e)
|
||||
* improve explanation for selections | [229c13a](https://github.com/undergroundwires/privacy.sexy/commit/229c13a195dee92e4a31731b7b41c319273a16f1)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.9.0...0.9.1)
|
||||
|
||||
## 0.9.0 (2021-01-15)
|
||||
|
||||
* refactor application.yaml to become an os definition #40 | [f7557bc](https://github.com/undergroundwires/privacy.sexy/commit/f7557bcc0faf44e8395b68c7eb14c5f715f07b92)
|
||||
* refactor folders to move "/state" (IApplicationState) inside "/context" (IApplicationContext) | [3467241](https://github.com/undergroundwires/privacy.sexy/commit/34672414c3e0757173036e351df0a73c1708ded5)
|
||||
* add scripts to prevent family safety monitoring | [e14bf2b](https://github.com/undergroundwires/privacy.sexy/commit/e14bf2bfa03efe28ff39942c9891fca605f13eed)
|
||||
* rework Cortana scripts to remove duplicates, better document and support Windows version 2004/2009 #43 | [7cc161c](https://github.com/undergroundwires/privacy.sexy/commit/7cc161c828a3fa49f6f254e31834a95a502b7aa2)
|
||||
* rename Application to CategoryCollection #40 | [6fe858d](https://github.com/undergroundwires/privacy.sexy/commit/6fe858d86aeb0f8b6d5ae5c2a5e3c25ff32e5f6f)
|
||||
* add script to clean previous windows installation #35 | [3455a2c](https://github.com/undergroundwires/privacy.sexy/commit/3455a2ca6ce13f9b0e866d88532a5c3d6de30d4d)
|
||||
* refactor to allow switching ICategoryCollection context #40 | [2e40605](https://github.com/undergroundwires/privacy.sexy/commit/2e40605d59eb764768457c6af561487e7ff09777)
|
||||
* fix typo causing uninstalling capabilities to fail #51 | [c299e95](https://github.com/undergroundwires/privacy.sexy/commit/c299e95bc6d588317b69a9efcf5752ff5c9c3926)
|
||||
* improve uninstalling apps to show errors and exit if taking ownership fails #51 | [72e925f](https://github.com/undergroundwires/privacy.sexy/commit/72e925fb6f908cd58fb50618f29726b3fb54a7f1)
|
||||
* move application.yaml to collections/windows.yaml #40 | [6b83dcb](https://github.com/undergroundwires/privacy.sexy/commit/6b83dcbf8fa08b4efe9974c7d7a667458f7c595c)
|
||||
* recommend onedrive removal on strict mode | [663d63b](https://github.com/undergroundwires/privacy.sexy/commit/663d63bde08dd1b0d43ec144c758399cec90ec70)
|
||||
* document app connector removal and recommend on strict mode | [9d009c4](https://github.com/undergroundwires/privacy.sexy/commit/9d009c40dd411c73c7ae032a78ec51490ecce024)
|
||||
* recommend removing cortana taskbar icon on standard mode | [7ec889e](https://github.com/undergroundwires/privacy.sexy/commit/7ec889e759df04bba99d3b6c4d0597809bd94058)
|
||||
* fix unintended null file creation #52 | [2428de2](https://github.com/undergroundwires/privacy.sexy/commit/2428de23ee02de987e7e6ec80ebd67be369d9048)
|
||||
* add initial macOS support #40 | [8a8b731](https://github.com/undergroundwires/privacy.sexy/commit/8a8b7319d539b31c1d8ad9eaf541762d64f02493)
|
||||
* add scripts to manage chromium based edge | [86a2b2f](https://github.com/undergroundwires/privacy.sexy/commit/86a2b2fda0b6a2565c550758c7c175fa795926b7)
|
||||
* update screenshot | [c318bd3](https://github.com/undergroundwires/privacy.sexy/commit/c318bd301a2cbebbf5cdba06c0f18ac291aa4788)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.8.2...0.9.0)
|
||||
|
||||
## 0.8.2 (2020-12-26)
|
||||
|
||||
* replace ampersand in "Movies & TV app" with "and" to prevent batch file from misinterpreting it (#45) | [52d4313](https://github.com/undergroundwires/privacy.sexy/commit/52d4313156d2dcbc508b7271e7d9dfd45723d7bc)
|
||||
* update dependencies to latest #46 | [d9e44e2](https://github.com/undergroundwires/privacy.sexy/commit/d9e44e25744e5d0aa01b8fc0f0af74c48027aea3)
|
||||
* fix type assignment error after typescript upgrade | [55f936f](https://github.com/undergroundwires/privacy.sexy/commit/55f936fee9f86757f63fa8952d89711feb247e5b)
|
||||
* correct typos (#48) | [a744415](https://github.com/undergroundwires/privacy.sexy/commit/a744415eb2ab65ee4f519f863fdd6a43953377bb)
|
||||
* in ci/cd, do not run security checks if PRs do not change dependencies #48 | [54ba4db](https://github.com/undergroundwires/privacy.sexy/commit/54ba4dbb0bf8f08f9479f8facb2e12c786c1bc51)
|
||||
* rename app launch tracking tweak to make it more clear #44 | [b3117c2](https://github.com/undergroundwires/privacy.sexy/commit/b3117c27f283c2d5a25fd94021a9f628a272cda6)
|
||||
* refactor capabilities to use a shared function #41 #47 | [c4ec6a1](https://github.com/undergroundwires/privacy.sexy/commit/c4ec6a1445d2fd5eb923c97b54aee01e272e13a8)
|
||||
* rename "disable" to "uninstall" for removing capabilities #47 | [8cd3352](https://github.com/undergroundwires/privacy.sexy/commit/8cd3352017f9dc85f8efcd7b450d90f555d3e92e)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.8.1...0.8.2)
|
||||
|
||||
## 0.8.1 (2020-11-16)
|
||||
|
||||
* refactor removing bloatware to use functions #41 | [ffa279f](https://github.com/undergroundwires/privacy.sexy/commit/ffa279f3dfe51db564f0a3859543eb212170e173)
|
||||
* fix reinstalling store apps by searching appx for all users | [2c5ab3e](https://github.com/undergroundwires/privacy.sexy/commit/2c5ab3ea7da159cfb9fbfbbb7cdd28afbee965ea)
|
||||
* fix clearing jump lists causing os to break and user pin removal #37 | [92c3dd9](https://github.com/undergroundwires/privacy.sexy/commit/92c3dd923257ac940eab6cbab858698ed55a09b7)
|
||||
* fix reinstalling store apps by searching appx for all users | [4e72673](https://github.com/undergroundwires/privacy.sexy/commit/4e7267337301fe4a0480ba0603218fca25c2d096)
|
||||
* refactor unused imports | [45b8dd9](https://github.com/undergroundwires/privacy.sexy/commit/45b8dd972b1edf9e263858c23b27e7a1d2e07077)
|
||||
* fix not being able to uninstall system apps | [31e08d2](https://github.com/undergroundwires/privacy.sexy/commit/31e08d231d52e2a691400468b7c599c142a29448)
|
||||
* fix wrong app names caused by wrong Microsoft docs | [e41e40c](https://github.com/undergroundwires/privacy.sexy/commit/e41e40c5bf01e2971d3054fcd3a48f8465a96622)
|
||||
* unrecommend some system apps and document more | [29c7704](https://github.com/undergroundwires/privacy.sexy/commit/29c7704e0bd38f6e9923cde84accb569b02d2dd6)
|
||||
* fix not being able to rename paths including brackets | [ad1872e](https://github.com/undergroundwires/privacy.sexy/commit/ad1872e7cd4ad7ef9facf33fadfa8c6a55065dd3)
|
||||
* fix errors when file already exists | [c26bc20](https://github.com/undergroundwires/privacy.sexy/commit/c26bc209eb167aa71cad10b7f3ea02d0dedd97b0)
|
||||
* move Microsoft.Appconnector to right category | [b247b12](https://github.com/undergroundwires/privacy.sexy/commit/b247b12c3f009aab4350e33f4779fd193e570050)
|
||||
* replace deprecated github ::set-env command | [ab7d617](https://github.com/undergroundwires/privacy.sexy/commit/ab7d617886a65fe4f3c2daa929168e5678ccae60)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.8.0...0.8.1)
|
||||
|
||||
## 0.8.0 (2020-11-01)
|
||||
|
||||
* add support for different recommendation levels: strict and standard | [14be301](https://github.com/undergroundwires/privacy.sexy/commit/14be3017c55ed5e0d9bdecb63fcc4e1131e79ab0)
|
||||
* Add GroupMe and Spotify removal option (#34) | [3785c62](https://github.com/undergroundwires/privacy.sexy/commit/3785c623f837b182d82fa383dfe7709722a67248)
|
||||
* switch places of download and copy buttons | [50fb290](https://github.com/undergroundwires/privacy.sexy/commit/50fb29038ae19b17ec006093db02cf1e568d53c3)
|
||||
* change "download" button to "save" on desktop | [07fc555](https://github.com/undergroundwires/privacy.sexy/commit/07fc555324d8bf4fa3594a9701daaa124a873153)
|
||||
* show icons on cards during indeterminate and fully selected states | [1072505](https://github.com/undergroundwires/privacy.sexy/commit/1072505219edc47d82a91f148d1f310f32869fea)
|
||||
* add scripts to increase cryptography, enable camera notifications and remove todo app (#36) | [4c68408](https://github.com/undergroundwires/privacy.sexy/commit/4c68408f1ec339dc8d39c7ab044f825a7f7185cb)
|
||||
* update recommendations to be safer and consistent | [d0019c2](https://github.com/undergroundwires/privacy.sexy/commit/d0019c2c9b1eea620e2e8e02b586903ce62b80e3)
|
||||
* rework disabling metadata retrieval | [ac70b06](https://github.com/undergroundwires/privacy.sexy/commit/ac70b063b8a15bc528256185792939685be6b36f)
|
||||
* add all dist folders in gitignore because of files auto-generated by vscode | [1a9db31](https://github.com/undergroundwires/privacy.sexy/commit/1a9db31c7778c3269a71c0bd9665827efda70a02)
|
||||
* add support for shared functions #41 | [8ce06fa](https://github.com/undergroundwires/privacy.sexy/commit/8ce06facbd54184402a4b1af3c7303e64db85b8a)
|
||||
* hide scrollbars on code area when not overflowing | [fd28eaa](https://github.com/undergroundwires/privacy.sexy/commit/fd28eaad061c75ea1aa7e0f0d60ea37a7e52f8c4)
|
||||
* update screenshot | [cfedcd7](https://github.com/undergroundwires/privacy.sexy/commit/cfedcd724cad7708b30c7390a7bca3b6313b6726)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.7.6...0.8.0)
|
||||
|
||||
## 0.7.6 (2020-10-18)
|
||||
|
||||
* add docs for default0 pointing to github discussion (#30) | [a3fc378](https://github.com/undergroundwires/privacy.sexy/commit/a3fc3782efd346b4c99d2a0b40df2eb0229f5b36)
|
||||
* add robots.txt to explicitly allow indexing | [4c2f749](https://github.com/undergroundwires/privacy.sexy/commit/4c2f74949b0758d33049bdfa4f0124a28958f8ea)
|
||||
* add more reversibility | [19a092d](https://github.com/undergroundwires/privacy.sexy/commit/19a092dd31fb3588277f1ab3120b409d98506752)
|
||||
* refactor to read more from package.json | [784a67a](https://github.com/undergroundwires/privacy.sexy/commit/784a67afff681bc19147d03c947de0e165d97e87)
|
||||
* simplify "why" section | [77c3d2b](https://github.com/undergroundwires/privacy.sexy/commit/77c3d2bbb8d13db86bb82ed0b5cbeaacfdea3db9)
|
||||
* update dependencies to latest | [11e0613](https://github.com/undergroundwires/privacy.sexy/commit/11e06131655398db08faeeacff62062e46e0dddd)
|
||||
* run tests on all operating systems: macos, ubuntu, windows | [d9d7f62](https://github.com/undergroundwires/privacy.sexy/commit/d9d7f62d81d4d8f95104d33211e82641884d711f)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.7.5...0.7.6)
|
||||
|
||||
## 0.7.5 (2020-09-14)
|
||||
|
||||
* fix reverting (reinstalling) capabilities not working | [939d838](https://github.com/undergroundwires/privacy.sexy/commit/939d838e3535bb1c9b00c8ea9dacb735ae41d700)
|
||||
* fix tests and checks are not running on PRs | [82d5091](https://github.com/undergroundwires/privacy.sexy/commit/82d509129b4e4a5df4b84786a0d6842a7d26e888)
|
||||
* fix the recycling bin option (#32) | [15db311](https://github.com/undergroundwires/privacy.sexy/commit/15db3118012a172a2191a2afad57084a65b34642)
|
||||
* fix rendering issue in older edge/IE | [6efed72](https://github.com/undergroundwires/privacy.sexy/commit/6efed72bf25c2ddf0901caab7f22966ca13cd47a)
|
||||
* fix pasting in search bar after page load showing no results | [d169434](https://github.com/undergroundwires/privacy.sexy/commit/d1694341578288eeaf8b80caf9296a38d76789f0)
|
||||
* fix typo | [7dd15ed](https://github.com/undergroundwires/privacy.sexy/commit/7dd15ed06433e0e6583ab0fa46a683ce6554bbea)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.7.4...0.7.5)
|
||||
|
||||
## 0.7.4 (2020-09-12)
|
||||
|
||||
* fix checked checkbox has blue border | [4ae385b](https://github.com/undergroundwires/privacy.sexy/commit/4ae385b7fcea9014a68442714b7d99e2ee7df7d0)
|
||||
* fix spectre protection getting single lined #31 | [22b23a9](https://github.com/undergroundwires/privacy.sexy/commit/22b23a9ece446c7f9abd4ede293051eb616ad50a)
|
||||
* fix missing reg value in denying app access to account | [3c13a9e](https://github.com/undergroundwires/privacy.sexy/commit/3c13a9e837e06e097450b31d7eb0c0e6bf20cefb)
|
||||
* fix wrong path in clear all firefox user profile settings | [ee66196](https://github.com/undergroundwires/privacy.sexy/commit/ee66196d9a60f27d17ae7f62d02b4f119a47e6e0)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.7.3...0.7.4)
|
||||
|
||||
## 0.7.3 (2020-09-12)
|
||||
|
||||
* fix vscode settings file override and add more configs | [a0d6172](https://github.com/undergroundwires/privacy.sexy/commit/a0d61728ead04b4455437f85820121a848db9e00)
|
||||
* fix nvidia tweak error message, categorize and add reversibility | [99a2035](https://github.com/undergroundwires/privacy.sexy/commit/99a2035fdb0766a4dfc2753133eab0d7666516cd)
|
||||
* improve CPU specific tweaks by conditional platform checks and reversibility | [8df5faf](https://github.com/undergroundwires/privacy.sexy/commit/8df5faf4ef05a49da63973bd0fbb5c5d07d5bd93)
|
||||
* fix wrong path to the main telemetry file | [de4ac97](https://github.com/undergroundwires/privacy.sexy/commit/de4ac978bdda79573b36d355697b8a028d2c0beb)
|
||||
* fix naming of firefox cleanup to mention profiles | [3ab48b1](https://github.com/undergroundwires/privacy.sexy/commit/3ab48b1cf5f7f934f07e468ef2318ccee07f530c)
|
||||
* add reversibility and more scripts to denying app access with better structure | [1d465ee](https://github.com/undergroundwires/privacy.sexy/commit/1d465ee3189d0e5a827453b3f0eb4361efe23770)
|
||||
* fix comment lines are being detected as duplicate in validation | [b6ccb59](https://github.com/undergroundwires/privacy.sexy/commit/b6ccb5927a20412976a54fd2215eb645092f98a8)
|
||||
* add more detailed error message | [1f11c39](https://github.com/undergroundwires/privacy.sexy/commit/1f11c39773c12eccfb3efb898b58c2f6f37ab9ca)
|
||||
* fix typo in a test | [1f19b25](https://github.com/undergroundwires/privacy.sexy/commit/1f19b2528a69383e63e579d2885f01cd804abf6c)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.7.2...0.7.3)
|
||||
|
||||
## 0.7.2 (2020-09-06)
|
||||
|
||||
* update onesync documentation and do not recommend it as it breaks other apps | [f36d8bf](https://github.com/undergroundwires/privacy.sexy/commit/f36d8bfc7848bb65ac0c641e318a689bf3816ccf)
|
||||
* add reversibility for biometric disabling and do not recommend it | [db74531](https://github.com/undergroundwires/privacy.sexy/commit/db74531cd4139615c6d595959217d3651f099019)
|
||||
* fix bad highlighting of selected nodes when using keyboard navigation | [255133a](https://github.com/undergroundwires/privacy.sexy/commit/255133af4dfae40171406648a3e2920f16d71cb3)
|
||||
* add reversibility to removing bloatware | [c7b2a70](https://github.com/undergroundwires/privacy.sexy/commit/c7b2a703128470a05f12c9c6e8002444def37ef8)
|
||||
* fix indeterminate state being lost | [1f266c3](https://github.com/undergroundwires/privacy.sexy/commit/1f266c33535f72b69c65985bf2eff27cd2c5a104)
|
||||
* fix wording in default text in text area | [ca63a09](https://github.com/undergroundwires/privacy.sexy/commit/ca63a0979ef55d07d09d9443e5cea9aa888870a5)
|
||||
* add best practice suggestion to come back | [f4885b6](https://github.com/undergroundwires/privacy.sexy/commit/f4885b6f1c82752f2143934e336d6d1b1af03015)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.7.1...0.7.2)
|
||||
|
||||
## 0.7.1 (2020-09-04)
|
||||
|
||||
* fix some browsers (including firefox) downloading the script as a text file | [8c17929](https://github.com/undergroundwires/privacy.sexy/commit/8c17929151f9c4fa5f48564492bbf400ced95eea)
|
||||
* rename screenshot image file | [b8682a8](https://github.com/undergroundwires/privacy.sexy/commit/b8682a852a14ed6cf49986695d9510b840ac9d3d)
|
||||
* fix new/changed script higlighting not working on production builds | [8c38dd7](https://github.com/undergroundwires/privacy.sexy/commit/8c38dd73d8c7b77d8d341c0389f4d7229f9b97fd)
|
||||
* refactor unused imports | [6badfef](https://github.com/undergroundwires/privacy.sexy/commit/6badfef9daace0c5de3fd33652a82bfe22261b11)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.7.0...0.7.1)
|
||||
|
||||
## 0.7.0 (2020-09-02)
|
||||
|
||||
* [search] better (multilined) message when there are no results | [ec15af0](https://github.com/undergroundwires/privacy.sexy/commit/ec15af01dd020b364c2174fe562fd66227c2320c)
|
||||
* [search] added clear/close button | [d6fa9a2](https://github.com/undergroundwires/privacy.sexy/commit/d6fa9a2a03c0ebe68b94f0b80cc52b4e200c9213)
|
||||
* move script generation to /generation | [5df4587](https://github.com/undergroundwires/privacy.sexy/commit/5df458739d076719e350ba194c4f3f772884fcdb)
|
||||
* add auto-highlighting of selected/updated code | [b789250](https://github.com/undergroundwires/privacy.sexy/commit/b789250cb89e2130b08e1a927df8181cf945dfeb)
|
||||
* prompt admin priviliges automatically | [f8ba5c4](https://github.com/undergroundwires/privacy.sexy/commit/f8ba5c46e4923d9c35f200f8a08aa6437f7c0ecc)
|
||||
* add removal of ghost (default0) telemetry user | [c262681](https://github.com/undergroundwires/privacy.sexy/commit/c262681011f39b4412669b6cf233476f676ca550)
|
||||
* add more windows defender tweaks, categorization and reversibility | [1a34c73](https://github.com/undergroundwires/privacy.sexy/commit/1a34c7374ba56bafa0209bbb55c81b233bb419ed)
|
||||
* fix NTP script documentation is on wrong place | [3060ebf](https://github.com/undergroundwires/privacy.sexy/commit/3060ebf79cf242370433495cc3e1878b7581b202)
|
||||
* updated dependencies to latest and audit fixes (#25) | [c628aa9](https://github.com/undergroundwires/privacy.sexy/commit/c628aa9aef8ab7c815661d3c1711e7fbc65c69a2)
|
||||
* categorize, fix and extend windows log files cleanup | [594a14d](https://github.com/undergroundwires/privacy.sexy/commit/594a14d6ca76cbd27a21877b8c373c1930589ca6)
|
||||
* add more OneDrive cleanup scripts and categorize them | [978d7d0](https://github.com/undergroundwires/privacy.sexy/commit/978d7d08638dd161082f239ed088b12302f29458)
|
||||
* add disabling firefox telemetry | [f8b8b4c](https://github.com/undergroundwires/privacy.sexy/commit/f8b8b4c97ab734d5ba7370894b694993924388da)
|
||||
* add disabling ccleaner telemetry | [018b7e2](https://github.com/undergroundwires/privacy.sexy/commit/018b7e270f207aac926cb12f8069ebfcdce193ce)
|
||||
* Add disabling of PowerShell 7+ telemetry (#29) | [456e40b](https://github.com/undergroundwires/privacy.sexy/commit/456e40bedf9afcc846f9b13f1ea144cef6115cf6)
|
||||
* categorize, fix, make scripts reversible in "UI for privacy", "security improvements" and "configure browsers" | [532915b](https://github.com/undergroundwires/privacy.sexy/commit/532915b95da9fecd6b981d91bf489359e4e53caa)
|
||||
* fix "Configure Defender" being in wrong category #28 | [f709d6a](https://github.com/undergroundwires/privacy.sexy/commit/f709d6a566ed7846b677b383863deda9680a2a9c)
|
||||
* do not hardcode capability versions and make them reversible | [2afef4e](https://github.com/undergroundwires/privacy.sexy/commit/2afef4ea3d0d3d09aa1fa1eedba8493680bd8f10)
|
||||
* exclude paint, wordpad and notepad from bloatware removal | [d235dee](https://github.com/undergroundwires/privacy.sexy/commit/d235dee95514a01745aef9479d07f88ffb4b40b8)
|
||||
* add reversibility on category level | [f51e885](https://github.com/undergroundwires/privacy.sexy/commit/f51e8859eeb32c944126d692cfe03a0320c8b568)
|
||||
* refactor unused imports & variables | [a23d28f](https://github.com/undergroundwires/privacy.sexy/commit/a23d28f2cfa2d64d45460697cf5ee9d6b5920752)
|
||||
* fix search (got broken in b789250) with tests and refactorings | [8bbe6eb](https://github.com/undergroundwires/privacy.sexy/commit/8bbe6ebf750f1a1cbab493fb99b5ea91f4e21609)
|
||||
* update the screenshot to show off highlighting | [b4aacea](https://github.com/undergroundwires/privacy.sexy/commit/b4aacea2a3e0bbcf2d8a79ff67f51c0f19e888a6)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.6.2...0.7.0)
|
||||
|
||||
## 0.6.2 (2020-08-16)
|
||||
|
||||
* 🐛 fixed disabling error reporting for november 2019 update | [5967347](https://github.com/undergroundwires/privacy.sexy/commit/5967347b80976a519f6f4eb1972a62f3e600df2b)
|
||||
* 🐛 fixed blank screen and icons on mac | [7fac0fe](https://github.com/undergroundwires/privacy.sexy/commit/7fac0fe79f252e8f9dda4f6f83cd6fa4ba2b539f)
|
||||
* 🐛 fixed removing onedrive does not delete scheduled tasks | [b6bfc25](https://github.com/undergroundwires/privacy.sexy/commit/b6bfc2572740c0cd46d3bc0058fa767dd5fa862e)
|
||||
* ⚙️ enhanced tweak to disable for office telemetry | [afc3bfb](https://github.com/undergroundwires/privacy.sexy/commit/afc3bfb3b8896f332c9a196973ded3dce8fd21e4)
|
||||
* ✨ added script to clear dotnet telemery | [1663bfe](https://github.com/undergroundwires/privacy.sexy/commit/1663bfeac7b6580b1335ca5fcf3587b69c080c72)
|
||||
* 🐛 fixed changing time server not working | [c69998c](https://github.com/undergroundwires/privacy.sexy/commit/c69998c7cb29ffcf40f0af03b73150736581da69)
|
||||
* 🔥 removed disabling ClickToRun as it breaks office | [3d3380f](https://github.com/undergroundwires/privacy.sexy/commit/3d3380f27ebeea53f17f49974aaa89300ffaf2dd)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.6.1...0.6.2)
|
||||
|
||||
## 0.6.1 (2020-08-09)
|
||||
|
||||
* updated documentation | [5963d2b](https://github.com/undergroundwires/privacy.sexy/commit/5963d2bac551083f9d16cce6b851abf0e8b88ce7)
|
||||
* fixed typo in footer | [5c15a7a](https://github.com/undergroundwires/privacy.sexy/commit/5c15a7a64aaf24578a32713dec491bf494216303)
|
||||
* more scripts can be reverted | [831c014](https://github.com/undergroundwires/privacy.sexy/commit/831c014f977515454ee6dc664d77a8c434495501)
|
||||
* moved windows connect now to security & recommended | [6049a2b](https://github.com/undergroundwires/privacy.sexy/commit/6049a2b834d8d17af741f8d8f8b07cd15153b001)
|
||||
* fixed mac / linux download links | [4c8be45](https://github.com/undergroundwires/privacy.sexy/commit/4c8be45e287b5ea009d6f828f7f327f37850569e)
|
||||
* tweaks to disable webcam, speech and compatibility telemetry | [a5dbe66](https://github.com/undergroundwires/privacy.sexy/commit/a5dbe66fc175e39397f296ab2ff703e9b0ab4d7c)
|
||||
* refactorings | [66d4d39](https://github.com/undergroundwires/privacy.sexy/commit/66d4d39d5bf3db305450514c6b6224654dafbfb2)
|
||||
* fixed removing onedrive does not clean start menu / quick access | [1cc1219](https://github.com/undergroundwires/privacy.sexy/commit/1cc12195a3e9a11c590d3ed64d80299b50f74838)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.6.0...0.6.1)
|
||||
|
||||
## 0.6.0 (2020-07-26)
|
||||
|
||||
* fixed dead links in documentation | [25ce236](https://github.com/undergroundwires/privacy.sexy/commit/25ce236a7737decaf2eb9b8c29a4c4f34d43f770)
|
||||
* runs tests on each push on the repository | [73c4268](https://github.com/undergroundwires/privacy.sexy/commit/73c426844a0330718a9ab7de12b61ca05e853323)
|
||||
* code area now shows "how" before "why" | [4ff4b52](https://github.com/undergroundwires/privacy.sexy/commit/4ff4b52202b1c5dbfe2b80580bbe7d93132ab05c)
|
||||
* support for desktop versions #20 | [04b9b59](https://github.com/undergroundwires/privacy.sexy/commit/04b9b59e14766ccd251474ad3710baf1f682fd49)
|
||||
* reworked on footer & removed github icon | [60a5a2a](https://github.com/undergroundwires/privacy.sexy/commit/60a5a2aa4026d384bef9e6a203f1b7514a269c33)
|
||||
* updated dependencies to latest | [45816a2](https://github.com/undergroundwires/privacy.sexy/commit/45816a2bccb3d11a50e3f2bc19c0a6cc2587deaa)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.5.0...0.6.0)
|
||||
|
||||
## 0.5.0 (2020-07-19)
|
||||
|
||||
* added ability to revert (#21) | [9c063d5](https://github.com/undergroundwires/privacy.sexy/commit/9c063d59defa6297c64f50b49403e8bd10620de9)
|
||||
* search placeholder shows total scripts | [1d5225d](https://github.com/undergroundwires/privacy.sexy/commit/1d5225de07186f853f4cf7aedd4998f5d00c107a)
|
||||
* do not collapse card when on "Search" and "Select" | [dd7e141](https://github.com/undergroundwires/privacy.sexy/commit/dd7e1416b4df54bf71b719d4654db88769dc0994)
|
||||
* opening a card scrolls to its content div | [31d2067](https://github.com/undergroundwires/privacy.sexy/commit/31d2067f076c3159483baec49975617dddbd158d)
|
||||
* all cards in same line now have same height | [a9f9e90](https://github.com/undergroundwires/privacy.sexy/commit/a9f9e9044385d9aed3b5551fc6c6823e813fd1e5)
|
||||
* patched loadash vulnerability (#18) | [92a7118](https://github.com/undergroundwires/privacy.sexy/commit/92a7118d1c5013312772e075b9ee5a79c93710b8)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.4.10...0.5.0)
|
||||
|
||||
## 0.4.10 (2020-07-15)
|
||||
|
||||
* fixed script errors & added tests | [9e722dd](https://github.com/undergroundwires/privacy.sexy/commit/9e722ddfb3825fb29d6298025baaaa033120d017)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.4.9...0.4.10)
|
||||
|
||||
## 0.4.9 (2020-07-14)
|
||||
|
||||
* disable office telemetry Disassembler0/Win10-Initial-Setup-Script#288 | [53cf595](https://github.com/undergroundwires/privacy.sexy/commit/53cf595e1726ee3de79137fd566978fd512d218f)
|
||||
* updated to may 2020 update | [909c44d](https://github.com/undergroundwires/privacy.sexy/commit/909c44d72a4a602ee8f27d06b6ec706c1e432ce1)
|
||||
* simplified docker builds | [f27a287](https://github.com/undergroundwires/privacy.sexy/commit/f27a2871d74e5117fc029be82caef12246e10879)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.4.8...0.4.9)
|
||||
|
||||
## 0.4.8 (2020-07-11)
|
||||
|
||||
* added more scripts #16 (#17) | [d8552c6](https://github.com/undergroundwires/privacy.sexy/commit/d8552c62ffea13ce62abce836c7dd4980eef6bb9)
|
||||
* stopping services before disabling #16 | [628c16e](https://github.com/undergroundwires/privacy.sexy/commit/628c16eb952495f5b3f6d794161b355f4b08b819)
|
||||
* can disable features, capabilities & remove onedrive #16 | [30efbcc](https://github.com/undergroundwires/privacy.sexy/commit/30efbcc621eb83dd5a9c1e66b8f1f5350eb95006)
|
||||
* updated one more typo (#19) | [d7a1325](https://github.com/undergroundwires/privacy.sexy/commit/d7a1325c0b7665ce712dc411965d00fc1d6fa384)
|
||||
* more tweaks #16 | [2c4eb78](https://github.com/undergroundwires/privacy.sexy/commit/2c4eb78c3f156cb0d033977cffbe7464697680f5)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.4.7...0.4.8)
|
||||
|
||||
## 0.4.7 (2020-06-30)
|
||||
|
||||
* removed HKU tweak as all HKU's are changed #10 | [c937af8](https://github.com/undergroundwires/privacy.sexy/commit/c937af8ee7da9aa95131e56abf7bf24800390fe6)
|
||||
* Fixed types + script in "Clear Windows log files" (#15) | [461a4f1](https://github.com/undergroundwires/privacy.sexy/commit/461a4f122b342369db5cc08c5e30961c64e68cdd)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.4.6...0.4.7)
|
||||
|
||||
## 0.4.6 (2020-06-16)
|
||||
|
||||
* Fixed Some More Issues (#12) | [52d5713](https://github.com/undergroundwires/privacy.sexy/commit/52d5713a99422cdf900aba819e49e998abac33cc)
|
||||
* removed failing continuous deployment #14 | [583c566](https://github.com/undergroundwires/privacy.sexy/commit/583c5660d6ac934b845a044e013357aa91f61c15)
|
||||
* Updated Some Tweaks (#11) | [0fc1845](https://github.com/undergroundwires/privacy.sexy/commit/0fc18459cde57684f00764815062f838f932aed5)
|
||||
* Updated Some More Tweaks (#13) | [019b838](https://github.com/undergroundwires/privacy.sexy/commit/019b838925e963b7ec052ac76c6faf5650b9eb67)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.4.5...0.4.6)
|
||||
|
||||
## 0.4.5 (2020-06-13)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.4.4...0.4.5)
|
||||
|
||||
## 0.4.4 (2020-05-24)
|
||||
|
||||
* fixed close card button not being visible & cleanup | [0d2efe5](https://github.com/undergroundwires/privacy.sexy/commit/0d2efe5b05aa965458b78b8fa43754ce2f4fe11b)
|
||||
* new footer with privacy policy | [e2ab124](https://github.com/undergroundwires/privacy.sexy/commit/e2ab124fb799f56ada3570fdc911361cb803e889)
|
||||
* one command to lint everything "npm run lint" | [bb98d20](https://github.com/undergroundwires/privacy.sexy/commit/bb98d20637cbf1d524ebb2973e308773006e3153)
|
||||
* fix "group by" overflows on smaller screens | [c668a97](https://github.com/undergroundwires/privacy.sexy/commit/c668a97950a1cb7c8bf2a7fd8a72d1101e65e8ce)
|
||||
* clicking outside of a card closes it | [aab8f21](https://github.com/undergroundwires/privacy.sexy/commit/aab8f21a8d8dbed54798af581e6e1ad9e86a4be1)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.4.3...0.4.4)
|
||||
|
||||
## 0.4.3 (2020-05-23)
|
||||
|
||||
* removed redundant documentation | [749a140](https://github.com/undergroundwires/privacy.sexy/commit/749a140eb8dba09cb67fec2f8dec937e66e3cff5)
|
||||
* fixed broke link | [97b7e03](https://github.com/undergroundwires/privacy.sexy/commit/97b7e03233d9718a8df30cb01ce06ca9489a0295)
|
||||
* simplified heading | [226074c](https://github.com/undergroundwires/privacy.sexy/commit/226074c5342f7463c06fcff1457d352ca30295a3)
|
||||
* reading version from package.json instead of version file #5 | [691f989](https://github.com/undergroundwires/privacy.sexy/commit/691f989682179016ddcbf55a05cded29155288c9)
|
||||
* automatically increases patch number #5 | [3e3bc07](https://github.com/undergroundwires/privacy.sexy/commit/3e3bc07576f7c7e74e3e11fc7d197cbb9a9fb8c0)
|
||||
* using deployment operations from aws-static-site-with-cd | [997be71](https://github.com/undergroundwires/privacy.sexy/commit/997be7113f676888892ffa35566d9ebb58a3e9ea)
|
||||
* automated using bump-everywhere + more quality checks (#8) | [4a91e8c](https://github.com/undergroundwires/privacy.sexy/commit/4a91e8ccd8a707bc6bea34ee28cff7fa4f66ee2f)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.4.2...0.4.3)
|
||||
|
||||
## 0.4.2 (2020-02-29)
|
||||
|
||||
* added missing semicolon for masking | [e63ac4a](https://github.com/undergroundwires/privacy.sexy/commit/e63ac4ae67da68243a525af149ff30e5d485b641)
|
||||
* set font on input | [0c39a06](https://github.com/undergroundwires/privacy.sexy/commit/0c39a06be5e4b0a2031ad5e9f5220dd669afee53)
|
||||
* shortened all HKEY paths | [802b36b](https://github.com/undergroundwires/privacy.sexy/commit/802b36bdd8dcc1f0a2853fe7da2ea2fccd69a88c)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.4.1...0.4.2)
|
||||
|
||||
## 0.4.1 (2020-01-11)
|
||||
|
||||
* fixed search bug | [31364bd](https://github.com/undergroundwires/privacy.sexy/commit/31364bdfec503af09ffbb58044a17dfb833fc8d9)
|
||||
* hide grouping while searching | [92f1a36](https://github.com/undergroundwires/privacy.sexy/commit/92f1a36bcb1e1fe7c90efe8ccd3ede55991e9d9c)
|
||||
* 👀🔍 showing search queries | [97a7747](https://github.com/undergroundwires/privacy.sexy/commit/97a7747933d2b515cc03ab8243e6a8ae702ef16a)
|
||||
* more efficient queries with single lowercase | [19813b6](https://github.com/undergroundwires/privacy.sexy/commit/19813b691746d98670823025c460480400e34b6e)
|
||||
* using right 🔍 input type | [0ce354e](https://github.com/undergroundwires/privacy.sexy/commit/0ce354ea0956391ad3f37b252daac1127bfc601a)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.4.0...0.4.1)
|
||||
|
||||
## 0.4.0 (2020-01-11)
|
||||
|
||||
* 🔍 support for search | [89862b2](https://github.com/undergroundwires/privacy.sexy/commit/89862b2775703257b9dc2e19fbebde2c0d0fbda0)
|
||||
* more scripts & better organized | [95baf31](https://github.com/undergroundwires/privacy.sexy/commit/95baf3175b0d2c7df516f7893a96346b94ac8eca)
|
||||
* refactorings | [e3f82e0](https://github.com/undergroundwires/privacy.sexy/commit/e3f82e069e305f6d94eab335470c8e7b44295dd6)
|
||||
* more margin for the scripts | [5ea46ec](https://github.com/undergroundwires/privacy.sexy/commit/5ea46ecbf52236953d19f09a8eade08b83e6cd34)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.3.0...0.4.0)
|
||||
|
||||
## 0.3.0 (2020-01-09)
|
||||
|
||||
* added description & more descriptive title | [9957634](https://github.com/undergroundwires/privacy.sexy/commit/99576340b648550149871e2c0fe0b0d8c2dd0d7c)
|
||||
* allow robots | [eee0e78](https://github.com/undergroundwires/privacy.sexy/commit/eee0e785ec2c5e6bed53d21b4126a57773e35dba)
|
||||
* removed unused references | [cfd888f](https://github.com/undergroundwires/privacy.sexy/commit/cfd888f3afc5c260a0a4a73f2843b86b9f1df2cd)
|
||||
* 🚫 disable NVIDIA telemetry | [ab28f4e](https://github.com/undergroundwires/privacy.sexy/commit/ab28f4ed8538d51e1777c86302a63a0cd9c3cb2a)
|
||||
* backwards compatibility for fonts | [4bc13e1](https://github.com/undergroundwires/privacy.sexy/commit/4bc13e11926a6df77079646499e799742153b4ab)
|
||||
* added back meta needed for responsiveness | [ed872ef](https://github.com/undergroundwires/privacy.sexy/commit/ed872ef3d9f6c92afc0ce0d06998c60463a8b4e8)
|
||||
* fancy-font is renamed to main and now used | [6825001](https://github.com/undergroundwires/privacy.sexy/commit/6825001c61426194dc363b96b57a321241f3ba57)
|
||||
* added support for grouping | [ec6b3c5](https://github.com/undergroundwires/privacy.sexy/commit/ec6b3c54072a77bb4305da1c234db6c649218b88)
|
||||
* less hyphens as it looks better on mobile | [e0b080a](https://github.com/undergroundwires/privacy.sexy/commit/e0b080af69157f46ba12e2c25e794f5384671b51)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.2.0...0.3.0)
|
||||
|
||||
## 0.2.0 (2020-01-06)
|
||||
|
||||
* added GitHub Actions badge for build & deploy | [a229aca](https://github.com/undergroundwires/privacy.sexy/commit/a229aca68a92bbcd8e8176ac1dd25ce03509e074)
|
||||
* more badges 📛🏆📜 | [090e831](https://github.com/undergroundwires/privacy.sexy/commit/090e8319091044e53484ba8338510f6fb7c3cb80)
|
||||
* typo fixes + whitespace refactorings | [e99f210](https://github.com/undergroundwires/privacy.sexy/commit/e99f210c9dcf61a21e445e2a331384b6066f2c98)
|
||||
* switched content information to "why" section | [beb3c83](https://github.com/undergroundwires/privacy.sexy/commit/beb3c8339f83a224ca66ad8a911a9265ffe7c9c0)
|
||||
* fixed contribution URL | [7b4277d](https://github.com/undergroundwires/privacy.sexy/commit/7b4277d7706ccf6ba7e4b7b01aa46f8e3852cfc6)
|
||||
* fixed wrong relation + lighter style | [8d05b03](https://github.com/undergroundwires/privacy.sexy/commit/8d05b03c9f3c9fc015be6615da8c283809712065)
|
||||
* better URL validation | [aff463d](https://github.com/undergroundwires/privacy.sexy/commit/aff463dd64fecff92a786fcba88621dff6b1cf73)
|
||||
* refactoring to new function | [c646c10](https://github.com/undergroundwires/privacy.sexy/commit/c646c102730481c3f4648eb714dc0a84ce35b13c)
|
||||
* optimized find queries & refactorings | [d38f6cd](https://github.com/undergroundwires/privacy.sexy/commit/d38f6cd6a8b33e11df854c7abea05974dc04d4ce)
|
||||
* 🎨 styled no JS error | [c359f1d](https://github.com/undergroundwires/privacy.sexy/commit/c359f1d89c6874b3cc94154b993e33f58bd32268)
|
||||
* simplified finding duplicates | [57037aa](https://github.com/undergroundwires/privacy.sexy/commit/57037aaefcc0e80f0f4719cea89568490a731028)
|
||||
* fixed maintainability badge URL | [aaea47e](https://github.com/undergroundwires/privacy.sexy/commit/aaea47e7d15fe41dea26968db0107a0c53d108f3)
|
||||
* fixed wrong line dumps | [5ccc7c5](https://github.com/undergroundwires/privacy.sexy/commit/5ccc7c59528885ae7729197df3dfa00f924a2b3f)
|
||||
* refactorings in parsing | [2aa3742](https://github.com/undergroundwires/privacy.sexy/commit/2aa3742e30646bf1d1f3779419d161c3fb6c4808)
|
||||
* using free function | [20020af](https://github.com/undergroundwires/privacy.sexy/commit/20020af7c1d8de13948d8761fd4e7f0affb2badb)
|
||||
* default selection is now none | [3140cc6](https://github.com/undergroundwires/privacy.sexy/commit/3140cc663b86394d543de90228aa53e6a304d8d9)
|
||||
* added hyphen lines for longer names | [cced601](https://github.com/undergroundwires/privacy.sexy/commit/cced601d686d550f4225018e5311b7433efbb5ae)
|
||||
* more descriptive subtitle | [2cf9214](https://github.com/undergroundwires/privacy.sexy/commit/2cf9214b14d9720f747a71b3864ba7a28acf0ff4)
|
||||
* added footer with version | [10a34fa](https://github.com/undergroundwires/privacy.sexy/commit/10a34fae2f1a219ec52db0c74edb39b46ebd8abc)
|
||||
* using font variables | [60e6348](https://github.com/undergroundwires/privacy.sexy/commit/60e6348dc8d53f1e81ebdb2ec0e1962aac1e9842)
|
||||
* code-gen refactorings | [246e753](https://github.com/undergroundwires/privacy.sexy/commit/246e753ddc9dc8bf630e538663584bf3423cc749)
|
||||
* added text when nothing is chosen | [a7da75d](https://github.com/undergroundwires/privacy.sexy/commit/a7da75d4428090423b692ce45423f5bd300d8442)
|
||||
|
||||
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.1.0...0.2.0)
|
||||
|
||||
## 0.1.0 (2019-12-31)
|
||||
|
||||
Initial release | [commits](https://github.com/undergroundwires/privacy.sexy/commit/4e7f244190c6ffbf7b20443e3e69cf2402c4268a)
|
||||
|
||||
34
CONTRIBUTING.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Contributing
|
||||
|
||||
- Love your input! Contributing to this project should be as easy and transparent as possible, whether it's:
|
||||
- Reporting a bug
|
||||
- Discussing the current state of the code
|
||||
- Submitting a fix
|
||||
- Proposing new features
|
||||
- Becoming a maintainer
|
||||
|
||||
## Pull request process
|
||||
|
||||
- [GitHub flow](https://guides.github.com/introduction/flow/index.html) with [GitOps](./img/architecture/gitops.png) is used
|
||||
- Your pull requests are actively welcomed.
|
||||
- The steps:
|
||||
1. Fork the repo and create your branch from master.
|
||||
2. If you've added code that should be tested, add tests.
|
||||
3. If you've changed APIs, update the documentation.
|
||||
4. Ensure the test suite passes.
|
||||
5. Make sure your code lints.
|
||||
6. Issue that pull request!
|
||||
- 🙏 DO
|
||||
- Document your changes in the pull request
|
||||
- ❗ DON'T
|
||||
- Do not update the versions, current version is only [set by the maintainer](./img/architecture/gitops.png) and updated automatically by [bump-everywhere](https://github.com/undergroundwires/bump-everywhere)
|
||||
|
||||
## License
|
||||
|
||||
By contributing, you agree that your contributions will be licensed under its [GNU General Public License v3.0](./LICENSE).
|
||||
|
||||
## Read more
|
||||
|
||||
- See [tests](./docs/tests.md) for testing
|
||||
- See [extend script](./README.md#extend-scripts) for quick steps to extend scripts
|
||||
- See [architecture overview](./README.md#architecture-overview) to deep dive into privacy.sexy codebase
|
||||
12
Dockerfile
@@ -1,20 +1,12 @@
|
||||
# +-+-+-+-+-+ +-+-+-+-+-+
|
||||
# |B|u|i|l|d| |S|t|a|g|e|
|
||||
# +-+-+-+-+-+ +-+-+-+-+-+
|
||||
# Build
|
||||
FROM node:lts-alpine as build-stage
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
# For testing purposes, it's easy to run http-server on lts-alpine such as continuing from here:
|
||||
# RUN npm install -g http-server
|
||||
# EXPOSE 8080
|
||||
# CMD [ "http-server", "dist" ]
|
||||
|
||||
# +-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+
|
||||
# |P|r|o|d|u|c|t|i|o|n| |S|t|a|g|e|
|
||||
# +-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+
|
||||
# Production stage
|
||||
FROM nginx:stable-alpine as production-stage
|
||||
COPY --from=build-stage /app/dist /usr/share/nginx/html
|
||||
EXPOSE 80
|
||||
|
||||
245
README.md
@@ -1,126 +1,175 @@
|
||||
# privacy.sexy
|
||||
|
||||

|
||||

|
||||
[](https://github.com/undergroundwires/privacy.sexy/issues)
|
||||
[](https://lgtm.com/projects/g/undergroundwires/privacy.sexy/context:javascript)
|
||||
[](https://codeclimate.com/github/undergroundwires/privacy.sexy/maintainability)
|
||||
> Enforce privacy & security best-practices on Windows and macOS, because privacy is sexy 🍑🍆
|
||||
|
||||
Web tool to generate scripts for enforcing privacy & security best-practices such as stopping data collection of Windows and different softwares on it.
|
||||
> because privacy is sexy 🍑🍆
|
||||
<!-- markdownlint-disable MD033 -->
|
||||
<p align="center">
|
||||
<a href="https://github.com/undergroundwires/privacy.sexy/blob/master/CONTRIBUTING.md">
|
||||
<img
|
||||
alt="contributions are welcome"
|
||||
src="https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat"
|
||||
/>
|
||||
</a>
|
||||
<!-- Code quality -->
|
||||
<br />
|
||||
<a href="https://lgtm.com/projects/g/undergroundwires/privacy.sexy/context:javascript">
|
||||
<img
|
||||
alt="Language grade: JavaScript/TypeScript"
|
||||
src="https://img.shields.io/lgtm/grade/javascript/g/undergroundwires/privacy.sexy.svg?logo=lgtm&logoWidth=18"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://codeclimate.com/github/undergroundwires/privacy.sexy/maintainability">
|
||||
<img
|
||||
alt="Maintainability"
|
||||
src="https://api.codeclimate.com/v1/badges/3a70b7ef602e2264342c/maintainability"
|
||||
/>
|
||||
</a>
|
||||
<!-- Tests -->
|
||||
<br />
|
||||
<a href="https://github.com/undergroundwires/privacy.sexy/actions/workflows/tests.unit.yaml">
|
||||
<img
|
||||
alt="Unit tests status"
|
||||
src="https://github.com/undergroundwires/privacy.sexy/workflows/unit-tests/badge.svg"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/undergroundwires/privacy.sexy/actions/workflows/tests.integration.yaml">
|
||||
<img
|
||||
alt="Integration tests status"
|
||||
src="https://github.com/undergroundwires/privacy.sexy/workflows/integration-tests/badge.svg"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/undergroundwires/privacy.sexy/actions/workflows/tests.e2e.yaml">
|
||||
<img
|
||||
alt="E2E tests status"
|
||||
src="https://github.com/undergroundwires/privacy.sexy/workflows/e2e-tests/badge.svg"
|
||||
/>
|
||||
</a>
|
||||
<!-- Checks -->
|
||||
<br />
|
||||
<a href="https://github.com/undergroundwires/privacy.sexy/actions/workflows/checks.quality.yaml">
|
||||
<img
|
||||
alt="Quality checks status"
|
||||
src="https://github.com/undergroundwires/privacy.sexy/workflows/quality-checks/badge.svg"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/undergroundwires/privacy.sexy/actions/workflows/checks.security.yaml">
|
||||
<img
|
||||
alt="Security checks status"
|
||||
src="https://github.com/undergroundwires/privacy.sexy/workflows/security-checks/badge.svg"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/undergroundwires/privacy.sexy/actions/workflows/checks.build.yaml">
|
||||
<img
|
||||
alt="Build checks status"
|
||||
src="https://github.com/undergroundwires/privacy.sexy/workflows/build-checks/badge.svg"
|
||||
/>
|
||||
</a>
|
||||
<!-- Release -->
|
||||
<br />
|
||||
<a href="https://github.com/undergroundwires/privacy.sexy/actions/workflows/release.git.yaml">
|
||||
<img
|
||||
alt="Git release status"
|
||||
src="https://github.com/undergroundwires/privacy.sexy/workflows/release-git/badge.svg"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/undergroundwires/privacy.sexy/actions/workflows/release.site.yaml">
|
||||
<img
|
||||
alt="Site release status"
|
||||
src="https://github.com/undergroundwires/privacy.sexy/workflows/release-site/badge.svg"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/undergroundwires/privacy.sexy/actions/workflows/release.desktop.yaml">
|
||||
<img
|
||||
alt="Desktop application release status"
|
||||
src="https://github.com/undergroundwires/privacy.sexy/workflows/release-desktop/badge.svg"
|
||||
/>
|
||||
</a>
|
||||
<!-- Others -->
|
||||
<br />
|
||||
<a href="https://github.com/undergroundwires/bump-everywhere">
|
||||
<img
|
||||
alt="Auto-versioned by bump-everywhere"
|
||||
src="https://github.com/undergroundwires/bump-everywhere/blob/master/badge.svg?raw=true"
|
||||
/>
|
||||
</a>
|
||||
</p>
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
[https://privacy.sexy](https://privacy.sexy)
|
||||
## Get started
|
||||
|
||||
## Why privacy.sexy
|
||||
- Online version at [https://privacy.sexy](https://privacy.sexy)
|
||||
- 💡 No need to run any compiled software on your computer.
|
||||
- Alternatively download offline version for [Windows](https://github.com/undergroundwires/privacy.sexy/releases/download/0.11.2/privacy.sexy-Setup-0.11.2.exe), [macOS](https://github.com/undergroundwires/privacy.sexy/releases/download/0.11.2/privacy.sexy-0.11.2.dmg) or [Linux](https://github.com/undergroundwires/privacy.sexy/releases/download/0.11.2/privacy.sexy-0.11.2.AppImage).
|
||||
- 💡 Single click to execute your script.
|
||||
- ❗ Come back regularly to apply latest version for stronger privacy and security.
|
||||
|
||||
- You don't need to run any compiled software on your system, just run the generated scripts.
|
||||
- It's open source, both application & infrastructure is 100% transparent
|
||||
- Fully automated C/CD pipeline to AWS for provisioning serverless infrastructure using GitHub actions.
|
||||
- Have full visibility into what the tweaks do as you enable them.
|
||||
- Easily extendable
|
||||
[](https://privacy.sexy)
|
||||
|
||||
## Why
|
||||
|
||||
- Rich tweak pool to harden security & privacy of the OS and other software on it
|
||||
- Free (both free as in beer and free as in speech)
|
||||
- No need to run any compiled software that has access to your system, just run the generated scripts
|
||||
- Have full visibility into what the tweaks do as you enable them
|
||||
- Ability to revert (undo) applied scripts
|
||||
- Everything is transparent: both application and its infrastructure are open-source and automated
|
||||
- Easily extendable with [own powerful templating language](./docs/templating.md)
|
||||
- Each script is independently executable without cross-dependencies
|
||||
|
||||
## Extend scripts
|
||||
|
||||
Fork it & add more scripts in `src/application/application.yml` and send a pull request 👌
|
||||
- You can either [create an issue](https://github.com/undergroundwires/privacy.sexy/issues/new/choose)
|
||||
- Or send a PR:
|
||||
1. Fork the repository
|
||||
2. Add more scripts in respective script collection in [collections](src/application/collections/) folder.
|
||||
- 📖 If you're unsure about the syntax you can refer to the [collection files | documentation](docs/collection-files.md).
|
||||
- 🙏 For any new script, please add `revertCode` and `docs` values if possible.
|
||||
3. Send a pull request 👌
|
||||
|
||||
## Commands
|
||||
|
||||
- Setup and run
|
||||
- For development:
|
||||
- `npm install` to project setup.
|
||||
- `npm run serve` to compile & hot-reload for development.
|
||||
- Production (using Docker):
|
||||
- Build `docker build -t undergroundwires/privacy.sexy .`
|
||||
- Run `docker run -it -p 8080:8080 --rm --name privacy.sexy-1 undergroundwires/privacy.sexy`
|
||||
- Prepare for production: `npm run build`
|
||||
- Run tests: `npm run test:unit`
|
||||
- Lint and fix files: `npm run lint`
|
||||
- Project setup: `npm install`
|
||||
- Testing
|
||||
- Run unit tests: `npm run test:unit`
|
||||
- Run integration tests: `npm run test:integration`
|
||||
- Run e2e (end-to-end) tests
|
||||
- Interactive mode with GUI: `npm run test:e2e`
|
||||
- Headless mode without GUI: `npm run test:e2e -- --headless`
|
||||
- Lint: `npm run lint`
|
||||
- **Desktop app**
|
||||
- Development: `npm run electron:serve`
|
||||
- Production: `npm run electron:build` to build an executable
|
||||
- **Webpage**
|
||||
- Development: `npm run serve` to compile & hot-reload for development.
|
||||
- Production: `npm run build` to prepare files for distribution.
|
||||
- Or run using Docker:
|
||||
1. Build: `docker build -t undergroundwires/privacy.sexy:0.11.2 .`
|
||||
2. Run: `docker run -it -p 8080:80 --rm --name privacy.sexy-0.11.2 undergroundwires/privacy.sexy:0.11.2`
|
||||
|
||||
## Architecture
|
||||
## Architecture overview
|
||||
|
||||
### Application
|
||||
|
||||
- Powered by **TypeScript** + **Vue.js** 💪
|
||||
- Powered by **TypeScript**, **Vue.js** and **Electron** 💪
|
||||
- and driven by **Domain-driven design**, **Event-driven architecture**, **Data-driven programming** concepts.
|
||||
- Application uses highly decoupled models & services in different DDD layers.
|
||||
- **Domain layer** is where the application is modelled with validation logic.
|
||||
- **Presentation Layer**
|
||||
- Consists of Vue.js components & UI stuff.
|
||||
- Event driven as in components simply listens to events from the state and act accordingly.
|
||||
- **Application Layer**
|
||||
- Keeps the application state
|
||||
- The [state](src/application/State/ApplicationState.ts) is a mutable singleton & event producer.
|
||||
- The application is defined & controlled in a [single YAML file](`\application\application.yaml`) (see [Data-driven programming](https://en.wikipedia.org/wiki/Data-driven_programming))
|
||||
- 📖 Read more on • [Presentation](./docs/presentation.md) • [Application](./docs/application.md)
|
||||
|
||||

|
||||

|
||||
|
||||
### AWS Infrastructure
|
||||
|
||||
- The application runs in AWS 100% serverless and automatically provisioned using [CloudFormation files](/aws) and GitHub Actions.
|
||||
- Maximum security & automation and minimum AWS costs were the highest priorities of the design.
|
||||
[](https://github.com/undergroundwires/aws-static-site-with-cd)
|
||||
|
||||

|
||||
- It uses infrastructure from the following repository: [aws-static-site-with-cd](https://github.com/undergroundwires/aws-static-site-with-cd)
|
||||
- Runs on AWS 100% serverless and automatically provisioned using [GitHub Actions](.github/workflows/).
|
||||
- Maximum security & automation and minimum AWS costs are the highest priorities of the design.
|
||||
|
||||
#### GitOps: CI/CD to AWS
|
||||
|
||||
- CI/CD is fully automated for this repo using different GIT events & GitHub actions.
|
||||
- Versioning, tagging, creation of `CHANGELOG.md` and releasing is automated using [bump-everywhere](https://github.com/undergroundwires/bump-everywhere) action
|
||||
- Everything that's merged in the master goes directly to production.
|
||||
- Deploy infrastructure ► Deploy web application ► Invalidate CloudFront Cache
|
||||
- See more at [build-and-deploy.yaml](.GitHub/workflows/build-and-deploy.yaml)
|
||||
- 📖 Read more on [CI/CD pipelines](./docs/ci-cd.md)
|
||||
|
||||

|
||||
|
||||
##### CloudFormation
|
||||
|
||||

|
||||
|
||||
- AWS infrastructure is defined as code with following files:
|
||||
- `iam-stack`: Creates & updates the deployment user.
|
||||
- Everything in IAM layer is fine-grained using least privileges principle.
|
||||
- Each deployment step has its own temporary credentials with own permissions.
|
||||
- `certificate-stack.yaml`
|
||||
- It'll generate SSL certification for the root domain and www subdomain.
|
||||
- ❗ It [must](https://aws.amazon.com/premiumsupport/knowledge-center/cloudfront-invalid-viewer-certificate/) be deployed in `us-east-1` to be able to be used by CloudFront by `web-stack`.
|
||||
- It uses CustomResource and a lambda instead of native `AWS::CertificateManager::Certificate` because:
|
||||
- Problem:
|
||||
- AWS variant waits until a certificate is validated.
|
||||
- There's no way to automate validation without workaround.
|
||||
- Solution:
|
||||
- Deploy a lambda that deploys the certificate (so we don't wait until certificate is validated)
|
||||
- Get DNS records to be used in validation & export it to be used later.
|
||||
- `web-stack.yaml`: It'll deploy S3 bucket and CloudFront in front of it.
|
||||
- `dns-stack.yaml`: It'll deploy Route53 hosted zone
|
||||
- Each time Route53 hosted zone is re-created it's required to update the DNS records in the domain registrar. See *Configure your domain registrar*.
|
||||
- I use cross stacks instead of single stack or nested stacks because:
|
||||
- Easier to test & maintain & smaller files and different lifecycles for different areas.
|
||||
- It allows to deploy web bucket in different region than others as other stacks are global (`us-east-1`) resources.
|
||||
|
||||
##### Initial deployment
|
||||
|
||||
- ❗ Prerequisite: A registered domain name for website.
|
||||
|
||||
1. **Configure build agent (GitHub actions)**
|
||||
- Deploy manually `iam-stack.yaml` with stack name `privacysexy-iam-stack` (to follow the convention)
|
||||
- It'll give you deploy user. Go to console & generate secret id + key (Security credentials => Create access key) for the user [IAM users](https://console.aws.amazon.com/iam/home#/users).
|
||||
- 🚶 Deploy secrets:
|
||||
- Add secret id & key in GitHub Secrets.
|
||||
- `AWS_DEPLOYMENT_USER_ACCESS_KEY_ID`, `AWS_DEPLOYMENT_USER_SECRET_ACCESS_KEY`
|
||||
- Add more secrets given from Outputs section of the CloudFormation stack.
|
||||
- Run GitHub actions to deploy rest of the application.
|
||||
- It'll run `certificate-stack.yaml` and then `iam-stack.yaml`.
|
||||
|
||||
2. **Configure your domain registrar**
|
||||
- ❗ **Web stack will fail** after DNS stack because you need to validate your domain.
|
||||
- 🚶 Go to your domain registrar and change name servers to NS values
|
||||
- `dns-stack.yaml` outputs those in CloudFormation stack.
|
||||
- You can alternatively find those in [Route53](https://console.aws.amazon.com/route53/home#hosted-zones)
|
||||
- When nameservers of your domain updated, the certification will get validated automatically, you can then delete the failed stack in CloudFormation & re-run the GitHub actions.
|
||||
|
||||
## Thank you for the awesome projects 🍺
|
||||
|
||||
- [Vue.js](https://vuejs.org/) the only big JavaScript framework that's not backed by companies that make money off your data.
|
||||
- [liquor-tree](https://GitHub.com/amsik/liquor-tree) for the awesome & super extensible tree component.
|
||||
- [Ace](https://ace.c9.io/) for code box.
|
||||
- [FileSaver.js](https://GitHub.com/eligrey/FileSaver.js) for save file dialog.
|
||||
- [chai](https://GitHub.com/chaijs/chai) & [mocha](https://GitHub.com/mochajs/mocha) for making testing fun.
|
||||
- [js-yaml-loader](https://GitHub.com/wwilsman/js-yaml-loader) for ahead of time loading `application.yml`
|
||||
- [v-tooltip](https://GitHub.com/Akryum/v-tooltip) takes seconds to have a tooltip, exactly what I needed.
|
||||
[](.github/workflows/)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<mxfile host="www.draw.io" modified="2019-12-27T14:40:11.720Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36" etag="6t_Q0ZRAKXZ_lLm1WdcF" version="12.4.3" type="device" pages="1"><diagram id="pFg2tUHn5hOZkmQyf_J4" name="Page-1">7Vvtd6I4F/9r+lEOEMLLR23rzJzdme3qPLMvXzwUomaLxA2x1f3rnwSIEoIWFdqd3bXnKLmEJNz7u69Jb8DtavuBhuvlZxKj5MY24+0NuLux7SAA/FsQdgXBD8yCsKA4LkjWgTDFf6GSKLttcIwypSMjJGF4rRIjkqYoYgotpJS8qN3mJFFnXYcLpBGmUZjo1F9wzJblW0DzQP+I8GIpZ7bM8s4qlJ1LQrYMY/JSIYH7G3BLCWHF1Wp7ixLBO8mX4rnxkbv7hVGUsjYPfB19Hf0+Wf6+DcbR9Mtksvm2hANYjPIcJpvyhe/IKsQpp03QAmeMhrRcPttJnqwJThmi9898ZsFe6waM9m9n8kYcZksUl40lWyWyE6PkCd2ShFBOSUnKBxzNcZJI0o0NoCn+OD0JH1HyQDLMMEn5vQiJSfmNZ0QZ5hL6sdbhkTBGVpUOwwQvxA1G1pxKNizBKZ9dAkVMEpZd9oPz91iL11xtFwLPBpnPcYSMDNFn/psZVHJlVpL4M7okSuGIhaBthVRK5gMiK8Tojncp79qeXzxSqgmQ+H85gA66BWlZwRu0S6iXMF/sRz4ggV+UYDgDGJatIUPDASWbNN7L+WWJGZquQ8GSuxfOPFX2e0xYNZmXMFCxwYEQe8GjaXbDXslNyd1A564r9bTKXuCYffEXvM5fiUW8yo1UlZvNEH9VM3KdGoXR0yKXXYXb8/zDu+STDbN1RUdkY463QoKjcj13S8aEFR4KTtjjKE5tA3M7PMccFdSI+Iz2OA5ZyH8EPeO/4Sr8i6SD8CUbZAylEU4ENTea4y/8xrRQqtmUT4m55s0ist7NZsNfprPbhGxijkvfWKeLDjAxMA1gBpWP76kgcW0dJIGOEUm7BiJ/bp/idPL8FMApjNFk+8N6+/NA18CcBWNK+DvXsdJo3ea8Z0XG/G8s5h9x0xZjpNwLHHg3tiv37jDlAxX4SQkVHNBM9RCYI9iku3s0KZ7gQsOt2eiKHog3LIMGy5btkiuN2K3bd45Ehxv1jGxohD5FYj0j3iyu1F6R4P485343RslXrZJrAg1w0i1UASdpnQNON0lTTjJHm+gJdY841xwC4J2HONvzLMv91yAuA90gDToq0mDgGa7zvmDTI0+JM/OBJDjadQu45mDzCJ7Kzn87KB0JvHV4rQsOdgIexwlU8EDdTEHfkAMr0WkH0VMjeFwNPBOODsRJcnH/uca3NFRUcH8GOzJXAKjmyrGC97VVnh6JCXHw+DTMQfc5THlErCfKjcjrW+4NYgRGdFjvbFWsdmbrsPVgcHvKfHZhTmquCDiNrggYsCHUBj0J2NcEfJ/OCYc9z07cRMR7j1y67kJcffz69WGqiRrFCyS1S5gEsiBpmNwfqCM1Wz70+ZEIkeai+wMxtit1NtwwogqW85zufq02fhODGVA277bl4EVrV209IIo5rwRY7k4m1YW6n+BVmZawkC4Qe11pBGNO4oKiJGT4Wa23NUm4fPRBOMFKFO2qlRPoBgb0LMf2i29PHbB4vXKMarWsNqzt2IbFAed5rmfbZmB558xSMEebJcfm/tUvh6ulB08TFOdeKXsPZBZOTtZH7avg5baEl/028OKiNZQigQoDD14GL+Aq8PIDeHrcngEli0//smpUil4GOxTSgYhyko1YnyALfzSukAZm0GHdybUMT5U2MC3dATZUI72+wmlbz/xVbq4pfg6jnZGhrZ6XfWcGRkK7amFO7Y30bWGAr+ZXPN9SXIt7oQfbF7nLce2gBp++bYqjgSqf63vyUKdw8aqHclvip5SXaXCnUD5zLaQsqxdI2Y5v+JWBaoUB4LYC2JDScFfptt6j4piC1HZvHLuG12LE2tNyeDKfZ6gfhOtpA0/1GE43ZMPfx4zROiG6vbw+Edhi9qsM7vl1JQ3grUMWIBoyCejUgrbVAHCuBlhWYCuyHgTXKcQbgECPxT9gttw8fv8BlPlqAEUiJi8tUxj88SqkT4NFzoAuYya3VhFym6sGPQVNz2vPu/92v8tcb/fTty+TzAzmA0uT+08UL/KjE8MoQpmwAJ9i/s6YvUkt+9azgDX+59WyKUkOpScNMg3AOn7IwndUhwVB220Qx+kJRXri9TG8JEK6JCaqHtnh6o0jxVdUoGXmH9FrQ5/3hzgajXtnNaXjOnfCf0DLUVMrv5N4qn46B/r2ZQEUcLiP24dh/FsZ1gXtykjnBlB8veryPbdNACXPSfhNHO3UsTbKWk8fhkkizvMJcYbxu6QRHUK+IYa6APID0zDBlTGS3CSGgeF7PAfJt0UDUxW7C4Im5J6rAC6oQd6EhgUq9bVeFMDR9NdvowD9Y1zfx3wz69+XKQc6ro/j/xSubUv11t2kxrC2twi9GuTaIhlaavbrgnbllXOxq53daGe8Zf4kz3H2j2V9k3TyXmb6WLLbV6xyXBF62I/oagcCng5FeisWNns53RL+L0M6eN6ldtIleNq6/cLcdQ4fLZEOLoQPdKChhtqOC7jN5jmV5zqO67mB86YIatjDeAU95xxYF42HkPGENc0pttn2GPujz1l1QNFVCSw0a9Jr2DgKGmogltnBGeVmruvVr32U/kI5f/tU4b3a/la506UKnwTapQ7gEOFAt7YRuPfWV2q5452y7bB+jKa1zgNvf8xvd5jJdDzXCuR3K6V/yxjb1l3Lp+FnTuAOhmro/K8w17owF8Zxfiaw2TZ2Yu4CDW+O/p87jfW6vqq+tqdBphrQlkKtVtM6s3DmSQunVPOOV/C6Co1bm8YTHa+Ibq6SoYxtNYvwgfumtSZfDmDWlF80Ofma6s/9CEVRk4bWFXmF4zhPfpqiEtVltghM3jHWsM/XPHHaZv9vsIXZP/wvMbj/Pw==</diagram></mxfile>
|
||||
@@ -1,211 +0,0 @@
|
||||
AWSTemplateFormatVersion: '2010-09-09'
|
||||
Description: Creates certificate for the root + www subdomain. !! It must be deployed in us-east-1 to be able to be used by CloudFront.
|
||||
|
||||
Parameters:
|
||||
|
||||
RootDomainName:
|
||||
Type: String
|
||||
Default: privacy.sexy
|
||||
Description: The root DNS name of the website e.g. privacy.sexy
|
||||
AllowedPattern: (?!-)[a-zA-Z0-9-.]{1,63}(?<!-)
|
||||
ConstraintDescription: Must be a valid root domain name
|
||||
|
||||
IamStackName:
|
||||
Type: String
|
||||
Default: privacysexy-iam-stack
|
||||
Description: Name of the IAM stack.
|
||||
|
||||
Resources:
|
||||
|
||||
# The lambda workaround exists to be able to automate certificate deployment.
|
||||
# Problem:
|
||||
# Normally AWS AWS::CertificateManager::Certificate waits until a certificate is validated
|
||||
# And there's no way to get validation DNS records from it to validate it.
|
||||
# Solution:
|
||||
# Deploy a lambda that deploys the certificate (so we don't wait until certificate is validated)
|
||||
# Get DNS records to be used in validation & export it to be used later.
|
||||
|
||||
AcmCertificateForHostedZone:
|
||||
Type: Custom::VerifiableCertificate #A Can use AWS::CloudFormation::CustomResource or Custom::String
|
||||
Properties:
|
||||
ServiceToken: !GetAtt ResolveCertificateLambda.Arn
|
||||
# Lambda gets the following data:
|
||||
RootDomainName: !Ref RootDomainName # Lambda will create both for root and www.root
|
||||
Tags:
|
||||
-
|
||||
Key: Name
|
||||
Value: !Ref RootDomainName
|
||||
-
|
||||
Key: Application
|
||||
Value: privacy.sexy
|
||||
|
||||
ResolveCertificateLambda:
|
||||
Type: AWS::Lambda::Function
|
||||
Properties:
|
||||
Description: Deploys certificate for root domain name + www and returns immediately arn + verification records.
|
||||
Role:
|
||||
Fn::ImportValue: !Join [':', [!Ref IamStackName, ResolveCertificateLambdaRoleArn]]
|
||||
FunctionName: !Sub ${AWS::StackName}-cert-resolver-lambda # StackName- required for role to function
|
||||
Handler: index.handler
|
||||
Runtime: nodejs12.x
|
||||
Timeout: 30
|
||||
Tags:
|
||||
-
|
||||
Key: Application
|
||||
Value: privacy.sexy
|
||||
Code:
|
||||
# Inline script is not the best way. Some variables are named shortly to not exceed the limit 4096 but it's the cheapest way (no s3 file)
|
||||
ZipFile: >
|
||||
'use strict';
|
||||
const aws = require('aws-sdk');
|
||||
const acm = new aws.ACM();
|
||||
const log = (t) => console.log(t);
|
||||
|
||||
exports.handler = async (event, context) => {
|
||||
log(`Request recieved:\n${JSON.stringify(event)}`);
|
||||
const userData = event.ResourceProperties;
|
||||
const rootDomain = userData.RootDomainName;
|
||||
let data = null;
|
||||
try {
|
||||
switch(event.RequestType) {
|
||||
case 'Create':
|
||||
data = await handleCreateAsync(rootDomain, userData.Tags);
|
||||
break;
|
||||
case 'Update':
|
||||
data = await handleUpdateAsync();
|
||||
break;
|
||||
case 'Delete':
|
||||
data = await handleDeleteAsync(rootDomain);
|
||||
break;
|
||||
}
|
||||
await sendResponseAsync(event, context, 'SUCCESS', data);
|
||||
} catch(error) {
|
||||
await sendResponseAsync(event, context, 'ERROR', {
|
||||
title: `Failed to ${event.RequestType}, see error`,
|
||||
error: error
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function handleCreateAsync(rootDomain, tags) {
|
||||
const { CertificateArn } = await acm.requestCertificate({
|
||||
DomainName: rootDomain,
|
||||
SubjectAlternativeNames: [`www.${rootDomain}`],
|
||||
Tags: tags,
|
||||
ValidationMethod: 'DNS',
|
||||
}).promise();
|
||||
log(`Cert requested:${CertificateArn}`);
|
||||
const waitAsync = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
const maxAttempts = 10;
|
||||
let options = undefined;
|
||||
for (let attempt = 0; attempt < maxAttempts && !options; attempt++) {
|
||||
await waitAsync(2000);
|
||||
const { Certificate } = await acm.describeCertificate({ CertificateArn }).promise();
|
||||
if(Certificate.DomainValidationOptions.filter((o) => o.ResourceRecord).length === 2) {
|
||||
options = Certificate.DomainValidationOptions;
|
||||
}
|
||||
}
|
||||
if(!options) {
|
||||
throw new Error(`No records after ${maxAttempts} attempts.`);
|
||||
}
|
||||
return getResponseData(options, CertificateArn, rootDomain);
|
||||
}
|
||||
|
||||
async function handleDeleteAsync(rootDomain) {
|
||||
const certs = await acm.listCertificates({}).promise();
|
||||
const cert = certs.CertificateSummaryList.find((cert) => cert.DomainName === rootDomain);
|
||||
if (cert) {
|
||||
await acm.deleteCertificate({ CertificateArn: cert.CertificateArn }).promise();
|
||||
log(`Deleted ${cert.CertificateArn}`);
|
||||
} else {
|
||||
log('Cannot find'); // Do not fail, delete can be called when e.g. CF fails before creating cert
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async function handleUpdateAsync() {
|
||||
throw new Error(`Not yet implemented update`);
|
||||
}
|
||||
|
||||
function getResponseData(options, arn, rootDomain) {
|
||||
const findRecord = (url) => options.find(option => option.DomainName === url).ResourceRecord;
|
||||
const root = findRecord(rootDomain);
|
||||
const www = findRecord(`www.${rootDomain}`);
|
||||
const data = {
|
||||
CertificateArn: arn,
|
||||
RootVerificationRecordName: root.Name,
|
||||
RootVerificationRecordValue: root.Value,
|
||||
WwwVerificationRecordName: www.Name,
|
||||
WwwVerificationRecordValue: www.Value,
|
||||
};
|
||||
return data;
|
||||
}
|
||||
|
||||
/* cfn-response can't async / await :( */
|
||||
async function sendResponseAsync(event, context, responseStatus, responseData, physicalResourceId) {
|
||||
return new Promise((s, f) => {
|
||||
var b = JSON.stringify({
|
||||
Status: responseStatus,
|
||||
Reason: `See the details in CloudWatch Log Stream: ${context.logStreamName}`,
|
||||
PhysicalResourceId: physicalResourceId || context.logStreamName,
|
||||
StackId: event.StackId,
|
||||
RequestId: event.RequestId,
|
||||
LogicalResourceId: event.LogicalResourceId,
|
||||
Data: responseData
|
||||
});
|
||||
log(`Response body:\n${b}`);
|
||||
var u = require("url").parse(event.ResponseURL);
|
||||
var r = require("https").request(
|
||||
{
|
||||
hostname: u.hostname,
|
||||
port: 443,
|
||||
path: u.path,
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"content-type": "",
|
||||
"content-length": b.length
|
||||
}
|
||||
}, (p) => {
|
||||
log(`Status code: ${p.statusCode}`);
|
||||
log(`Status message: ${p.statusMessage}`);
|
||||
s(context.done());
|
||||
});
|
||||
r.on("error", (e) => {
|
||||
log(`request failed: ${e}`);
|
||||
f(context.done(e));
|
||||
});
|
||||
r.write(b);
|
||||
r.end();
|
||||
});
|
||||
}
|
||||
|
||||
Outputs:
|
||||
CertificateArn:
|
||||
Description: The Amazon Resource Name (ARN) of an AWS Certificate Manager (ACM) certificate.
|
||||
Value: !GetAtt AcmCertificateForHostedZone.CertificateArn
|
||||
Export:
|
||||
Name: !Join [':', [ !Ref 'AWS::StackName', CertificateArn ]]
|
||||
|
||||
RootVerificationRecordName:
|
||||
Description: Name for root domain CNAME verification record
|
||||
Value: !GetAtt AcmCertificateForHostedZone.RootVerificationRecordName
|
||||
Export:
|
||||
Name: !Join [':', [ !Ref 'AWS::StackName', RootVerificationRecordName ]]
|
||||
|
||||
RootVerificationRecordValue:
|
||||
Description: Value for root domain name CNAME verification record
|
||||
Value: !GetAtt AcmCertificateForHostedZone.RootVerificationRecordValue
|
||||
Export:
|
||||
Name: !Join [':', [ !Ref 'AWS::StackName', RootVerificationRecordValue ]]
|
||||
|
||||
WwwVerificationRecordName:
|
||||
Description: Name for www domain name CNAME verification record
|
||||
Value: !GetAtt AcmCertificateForHostedZone.WwwVerificationRecordName
|
||||
Export:
|
||||
Name: !Join [':', [ !Ref 'AWS::StackName', WwwVerificationRecordName ]]
|
||||
|
||||
WwwVerificationRecordValue:
|
||||
Description: Value for www domain name CNAME verification record
|
||||
Value: !GetAtt AcmCertificateForHostedZone.WwwVerificationRecordValue
|
||||
Export:
|
||||
Name: !Join [':', [ !Ref 'AWS::StackName', WwwVerificationRecordValue ]]
|
||||
@@ -1,61 +0,0 @@
|
||||
AWSTemplateFormatVersion: '2010-09-09'
|
||||
Description: Creates hosted zone & sets up records for the CloudFront URL.
|
||||
|
||||
Parameters:
|
||||
|
||||
RootDomainName:
|
||||
Type: String
|
||||
Default: privacy.sexy
|
||||
Description: The root DNS name of the website e.g. privacy.sexy
|
||||
AllowedPattern: (?!-)[a-zA-Z0-9-.]{1,63}(?<!-)
|
||||
ConstraintDescription: Must be a valid root domain name
|
||||
|
||||
CertificateStackName:
|
||||
Type: String
|
||||
Default: privacysexy-certificate-stack
|
||||
Description: Name of the certificate stack.
|
||||
|
||||
Resources:
|
||||
|
||||
DNSHostedZone:
|
||||
Type: AWS::Route53::HostedZone
|
||||
Properties:
|
||||
Name: !Ref RootDomainName
|
||||
HostedZoneConfig:
|
||||
Comment: !Join ['', ['Hosted zone for ', !Ref RootDomainName]]
|
||||
HostedZoneTags:
|
||||
-
|
||||
Key: Application
|
||||
Value: privacy.sexy
|
||||
|
||||
CertificateValidationDNSRecords:
|
||||
Type: AWS::Route53::RecordSetGroup
|
||||
Properties:
|
||||
HostedZoneId: !Ref DNSHostedZone
|
||||
RecordSets:
|
||||
-
|
||||
Name:
|
||||
Fn::ImportValue: !Join [':', [!Ref CertificateStackName, RootVerificationRecordName]]
|
||||
Type: 'CNAME'
|
||||
TTL: '60'
|
||||
ResourceRecords:
|
||||
- Fn::ImportValue: !Join [':', [!Ref CertificateStackName, RootVerificationRecordValue]]
|
||||
-
|
||||
Name:
|
||||
Fn::ImportValue: !Join [':', [!Ref CertificateStackName, WwwVerificationRecordName]]
|
||||
Type: 'CNAME'
|
||||
TTL: '60'
|
||||
ResourceRecords:
|
||||
- Fn::ImportValue: !Join [':', [!Ref CertificateStackName, WwwVerificationRecordValue]]
|
||||
|
||||
Outputs:
|
||||
|
||||
DNSHostedZoneNameServers:
|
||||
Description: Name servers to update in domain registrar.
|
||||
Value: !Join [' ', !GetAtt DNSHostedZone.NameServers]
|
||||
|
||||
DNSHostedZoneId:
|
||||
Description: The ID of the hosted zone that you want to create the record in.
|
||||
Value: !Ref DNSHostedZone
|
||||
Export:
|
||||
Name: !Join [':', [ !Ref 'AWS::StackName', DNSHostedZoneId ]]
|
||||
@@ -1,496 +0,0 @@
|
||||
AWSTemplateFormatVersion: '2010-09-09'
|
||||
Description: |-
|
||||
> Deploys the identity management for the deployment
|
||||
|
||||
# Granulatiy cheatsheet: https://iam.cloudonaut.io/
|
||||
|
||||
Parameters:
|
||||
WebStackName:
|
||||
Type: String
|
||||
Default: privacysexy-web-stack
|
||||
Description: Name of the web stack.
|
||||
DnsStackName:
|
||||
Type: String
|
||||
Default: privacysexy-dns-stack
|
||||
Description: Name of the DNS stack.
|
||||
CertificateStackName:
|
||||
Type: String
|
||||
Default: privacysexy-certificate-stack
|
||||
Description: Name of the IAM stack.
|
||||
|
||||
Resources:
|
||||
|
||||
# -----------------------------
|
||||
# ------ User & Group ---------
|
||||
# -----------------------------
|
||||
DeploymentGroup:
|
||||
Type: AWS::IAM::Group
|
||||
Properties:
|
||||
# GroupName: No hardcoded naming because of easier CloudFormation management
|
||||
ManagedPolicyArns:
|
||||
- !Ref AllowValidateTemplatePolicy
|
||||
|
||||
DeploymentUser:
|
||||
Type: AWS::IAM::User
|
||||
Properties:
|
||||
# # UserName: No hardcoded naming because of easier CloudFormation management
|
||||
# # Policies: Assing policies on group level
|
||||
Tags:
|
||||
-
|
||||
Key: Application
|
||||
Value: privacy.sexy
|
||||
|
||||
AddDeploymentUserToDeploymentGroup:
|
||||
Type: AWS::IAM::UserToGroupAddition
|
||||
Properties:
|
||||
GroupName: !Ref DeploymentGroup
|
||||
Users:
|
||||
- !Ref DeploymentUser
|
||||
|
||||
# -----------------------------
|
||||
# ----------- Roles -----------
|
||||
# -----------------------------
|
||||
IamStackDeployRole:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
Description: Allows to deploy IAM stack
|
||||
AssumeRolePolicyDocument:
|
||||
Statement:
|
||||
-
|
||||
Effect: Allow
|
||||
Principal:
|
||||
AWS: !GetAtt DeploymentUser.Arn
|
||||
Action: sts:AssumeRole
|
||||
Tags:
|
||||
-
|
||||
Key: Application
|
||||
Value: privacy.sexy
|
||||
ManagedPolicyArns:
|
||||
- !Ref CloudFormationDeployPolicy
|
||||
- !Ref PolicyDeployPolicy
|
||||
- !Ref IamStackDeployPolicy
|
||||
|
||||
CertificateStackDeployRole:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
Description: Allows to deploy certificate stack
|
||||
AssumeRolePolicyDocument:
|
||||
Statement:
|
||||
-
|
||||
Effect: Allow
|
||||
Principal:
|
||||
AWS: !GetAtt DeploymentUser.Arn
|
||||
Action: sts:AssumeRole
|
||||
Tags:
|
||||
-
|
||||
Key: Application
|
||||
Value: privacy.sexy
|
||||
ManagedPolicyArns:
|
||||
- !Ref CloudFormationDeployPolicy
|
||||
- !Ref LambdaBackedCustomResourceDeployPolicy
|
||||
|
||||
DnsStackDeployRole:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
Description: Allows to deploy DNS stack
|
||||
AssumeRolePolicyDocument:
|
||||
Statement:
|
||||
-
|
||||
Effect: Allow
|
||||
Principal:
|
||||
AWS: !GetAtt DeploymentUser.Arn
|
||||
Action: sts:AssumeRole
|
||||
Tags:
|
||||
-
|
||||
Key: Application
|
||||
Value: privacy.sexy
|
||||
ManagedPolicyArns:
|
||||
- !Ref CloudFormationDeployPolicy
|
||||
- !Ref DnsStackDeployPolicy
|
||||
|
||||
WebStackDeployRole:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
Description: Allows to deploy web stack
|
||||
AssumeRolePolicyDocument:
|
||||
Statement:
|
||||
-
|
||||
Effect: Allow
|
||||
Principal:
|
||||
AWS: !GetAtt DeploymentUser.Arn
|
||||
Action: sts:AssumeRole
|
||||
Tags:
|
||||
-
|
||||
Key: Application
|
||||
Value: privacy.sexy
|
||||
ManagedPolicyArns:
|
||||
- !Ref CloudFormationDeployPolicy
|
||||
- !Ref WebStackDeployPolicy
|
||||
|
||||
S3SiteDeployRole:
|
||||
Type: 'AWS::IAM::Role'
|
||||
Properties:
|
||||
Description: "Allows to deploy website to S3"
|
||||
AssumeRolePolicyDocument:
|
||||
Statement:
|
||||
-
|
||||
Effect: Allow
|
||||
Principal:
|
||||
AWS: !GetAtt DeploymentUser.Arn
|
||||
Action: sts:AssumeRole
|
||||
Tags:
|
||||
-
|
||||
Key: Application
|
||||
Value: privacy.sexy
|
||||
ManagedPolicyArns:
|
||||
- !Ref S3SiteDeployPolicy
|
||||
- !Ref StackExportReaderPolicy
|
||||
|
||||
CloudFrontSiteDeployRole:
|
||||
Type: 'AWS::IAM::Role'
|
||||
Properties:
|
||||
Description: "Allows to informs to CloudFront to renew its cache from S3"
|
||||
AssumeRolePolicyDocument:
|
||||
Statement:
|
||||
-
|
||||
Effect: Allow
|
||||
Principal:
|
||||
AWS: !GetAtt DeploymentUser.Arn
|
||||
Action: sts:AssumeRole
|
||||
Tags:
|
||||
-
|
||||
Key: Application
|
||||
Value: privacy.sexy
|
||||
ManagedPolicyArns:
|
||||
- !Ref CloudFrontInvalidationPolicy
|
||||
- !Ref StackExportReaderPolicy
|
||||
|
||||
ResolveCertificateLambdaRole: # See certificate stack
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
Description: Allow deployment of certificates
|
||||
AssumeRolePolicyDocument:
|
||||
Statement:
|
||||
-
|
||||
Effect: Allow
|
||||
Principal:
|
||||
Service: lambda.amazonaws.com
|
||||
Action: sts:AssumeRole
|
||||
ManagedPolicyArns:
|
||||
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
|
||||
- !Ref CertificateDeployPolicy
|
||||
|
||||
# --------------------------------
|
||||
# ----------- Policies -----------
|
||||
# --------------------------------
|
||||
|
||||
AllowValidateTemplatePolicy:
|
||||
Type: AWS::IAM::ManagedPolicy
|
||||
Properties:
|
||||
Description: "No read & writes to resources, reveals just basic CloudFormation API to be used for validating templates"
|
||||
# ManagedPolicyName: No hardcoded naming because of easier CloudFormation management
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
-
|
||||
Sid: AllowCloudFormationTemplateValidation
|
||||
Effect: Allow
|
||||
Action:
|
||||
- cloudformation:ValidateTemplate
|
||||
Resource: '*'
|
||||
|
||||
CloudFormationDeployPolicy:
|
||||
Type: AWS::IAM::ManagedPolicy
|
||||
Properties:
|
||||
Description: "Allows deploying CloudFormation using CLI command 'aws cloudformation deploy' (with change sets)"
|
||||
# ManagedPolicyName: No hardcoded naming because of easier CloudFormation management
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
-
|
||||
Sid: AllowCloudFormationStackOperations
|
||||
Effect: Allow
|
||||
Action:
|
||||
- cloudformation:GetTemplateSummary
|
||||
- cloudformation:DescribeStacks
|
||||
- cloudformation:CreateChangeSet
|
||||
- cloudformation:ExecuteChangeSet
|
||||
- cloudformation:DescribeChangeSet
|
||||
Resource:
|
||||
- !Sub arn:aws:cloudformation:*:${AWS::AccountId}:stack/${WebStackName}/*
|
||||
- !Sub arn:aws:cloudformation:*:${AWS::AccountId}:stack/${DnsStackName}/*
|
||||
- !Sub arn:aws:cloudformation:*:${AWS::AccountId}:stack/${AWS::StackName}/*
|
||||
- !Sub arn:aws:cloudformation:*:${AWS::AccountId}:stack/${CertificateStackName}/*
|
||||
|
||||
IamStackDeployPolicy:
|
||||
Type: AWS::IAM::ManagedPolicy
|
||||
Properties:
|
||||
Description: Allows deploying IAM CloudFormation stack.
|
||||
# ManagedPolicyName: No hardcoded naming because of easier CloudFormation management
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
-
|
||||
Sid: AllowUserArnExport
|
||||
Effect: Allow
|
||||
Action:
|
||||
- iam:GetUser
|
||||
Resource:
|
||||
- !GetAtt DeploymentUser.Arn
|
||||
-
|
||||
Sid: AllowTagging
|
||||
Effect: Allow
|
||||
Action:
|
||||
- iam:TagResource
|
||||
Resource:
|
||||
- !Sub arn:aws:cloudformation::${AWS::AccountId}:stack/${AWS::StackName}/*
|
||||
- !GetAtt DeploymentUser.Arn
|
||||
-
|
||||
Sid: AllowRoleDeployment
|
||||
Effect: Allow
|
||||
Action:
|
||||
- iam:CreateRole
|
||||
Resource:
|
||||
- !Sub arn:aws:iam::${AWS::AccountId}:role/${AWS::StackName}-*
|
||||
|
||||
LambdaBackedCustomResourceDeployPolicy:
|
||||
Type: AWS::IAM::ManagedPolicy
|
||||
Properties:
|
||||
Description: Allows deploying a lambda-backed custom resource.
|
||||
# ManagedPolicyName: # ManagedPolicyName: No hardcoded naming because of easier CloudFormation management
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
-
|
||||
Sid: AllowLambdaDeployment
|
||||
Effect: Allow
|
||||
Action:
|
||||
- lambda:GetFunction
|
||||
- lambda:DeleteFunction
|
||||
- lambda:CreateFunction
|
||||
- lambda:GetFunctionConfiguration
|
||||
- lambda:InvokeFunction
|
||||
Resource:
|
||||
- !Sub arn:aws:lambda:*:${AWS::AccountId}:function:${CertificateStackName}*
|
||||
-
|
||||
Sid: AllowPassingLambdaRole
|
||||
Effect: Allow
|
||||
Action:
|
||||
- iam:PassRole
|
||||
Resource:
|
||||
- !GetAtt ResolveCertificateLambdaRole.Arn
|
||||
|
||||
CertificateDeployPolicy:
|
||||
Type: AWS::IAM::ManagedPolicy
|
||||
Properties:
|
||||
Description: Allows deploying certifications stack.
|
||||
# ManagedPolicyName: # ManagedPolicyName: No hardcoded naming because of easier CloudFormation management
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
-
|
||||
Sid: AllowCertificateDeployment
|
||||
Effect: Allow
|
||||
Action:
|
||||
- acm:RequestCertificate
|
||||
- acm:DescribeCertificate
|
||||
- acm:DeleteCertificate
|
||||
- acm:AddTagsToCertificate
|
||||
- acm:ListCertificates
|
||||
Resource: '*' # Certificate Manager does not support resource level IAM
|
||||
|
||||
PolicyDeployPolicy:
|
||||
Type: AWS::IAM::ManagedPolicy
|
||||
Properties:
|
||||
Description: Allows deployment of policies
|
||||
# ManagedPolicyName: Commented out because CloudFormation requires to rename when replacing custom-named resource
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
-
|
||||
Sid: AllowPolicyUpdates
|
||||
Effect: Allow
|
||||
Action:
|
||||
- iam:ListPolicyVersions
|
||||
- iam:CreatePolicyVersion
|
||||
- iam:DeletePolicyVersion
|
||||
- iam:CreatePolicy
|
||||
- iam:DeletePolicy
|
||||
- iam:GetPolicy
|
||||
Resource:
|
||||
- !Sub arn:aws:iam::${AWS::AccountId}:policy/${AWS::StackName}-* # when ManagedPolicyName is not given policies get name like StackName-*
|
||||
-
|
||||
Sid: AllowPoliciesOnRoles
|
||||
Effect: Allow
|
||||
Action:
|
||||
- iam:AttachRolePolicy
|
||||
- iam:DetachRolePolicy
|
||||
- iam:GetRole
|
||||
Resource:
|
||||
- !Sub arn:aws:iam::${AWS::AccountId}:role/${AWS::StackName}-*
|
||||
-
|
||||
Sid: AllowPolicyAssigmentToGroup
|
||||
Effect: Allow
|
||||
Action:
|
||||
- iam:AttachGroupPolicy
|
||||
- iam:DetachGroupPolicy
|
||||
Resource:
|
||||
- !GetAtt DeploymentGroup.Arn
|
||||
-
|
||||
Sid: AllowGettingGroupInformation
|
||||
Effect: Allow
|
||||
Action:
|
||||
- iam:GetGroup
|
||||
Resource: !Sub arn:aws:iam::${AWS::AccountId}:group/${DeploymentGroup}
|
||||
|
||||
DnsStackDeployPolicy:
|
||||
Type: AWS::IAM::ManagedPolicy
|
||||
Properties:
|
||||
Description: Allows deployment of DNS stack
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
-
|
||||
Sid: AllowHostedZoneDeployment
|
||||
Effect: Allow
|
||||
Action:
|
||||
- route53:CreateHostedZone
|
||||
- route53:ListQueryLoggingConfigs
|
||||
- route53:DeleteHostedZone
|
||||
- route53:GetChange
|
||||
- route53:ChangeTagsForResource
|
||||
- route53:GetHostedZone
|
||||
- route53:ChangeResourceRecordSets
|
||||
Resource: '*' # Does not support resource-level permissions https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/access-control-overview.html#access-control-manage-access-intro-resource-policies
|
||||
|
||||
WebStackDeployPolicy:
|
||||
# We need a role to run s3:PutBucketPolicy, IAM users cannot run it. See https://stackoverflow.com/a/48551383
|
||||
Type: AWS::IAM::ManagedPolicy
|
||||
Properties:
|
||||
Description: Allows deployment of web stack
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
-
|
||||
Sid: AllowCloudFrontOAIDeployment
|
||||
Effect: Allow
|
||||
Action:
|
||||
- cloudfront:GetCloudFrontOriginAccessIdentity
|
||||
- cloudfront:CreateCloudFrontOriginAccessIdentity
|
||||
- cloudfront:GetCloudFrontOriginAccessIdentityConfig
|
||||
- cloudfront:DeleteCloudFrontOriginAccessIdentity
|
||||
Resource: '*' # Does not support resource-level permissions https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cf-api-permissions-ref.html
|
||||
-
|
||||
Sid: AllowCloudFrontDistributionDeployment
|
||||
Effect: Allow
|
||||
Action:
|
||||
- cloudfront:CreateDistribution
|
||||
- cloudfront:DeleteDistribution
|
||||
- cloudfront:UpdateDistribution
|
||||
- cloudfront:GetDistribution
|
||||
- cloudfront:TagResource
|
||||
- cloudfront:UpdateCloudFrontOriginAccessIdentity
|
||||
Resource: !Sub arn:aws:cloudfront::${AWS::AccountId}:*
|
||||
-
|
||||
Sid: AllowS3BucketPolicyAccess
|
||||
Effect: Allow
|
||||
Action:
|
||||
- s3:CreateBucket
|
||||
- s3:DeleteBucket
|
||||
- s3:PutBucketWebsite
|
||||
- s3:DeleteBucketPolicy
|
||||
- s3:PutBucketPolicy
|
||||
- s3:GetBucketPolicy
|
||||
Resource: !Sub arn:aws:s3:::${WebStackName}*
|
||||
-
|
||||
Sid: AllowRecordDeploymentToRoute53
|
||||
Effect: Allow
|
||||
Action:
|
||||
- route53:GetHostedZone
|
||||
- route53:ChangeResourceRecordSets
|
||||
- route53:GetChange
|
||||
- route53:ListResourceRecordSets
|
||||
Resource: '*' # Does not support resource-level permissions https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/access-control-overview.html#access-control-manage-access-intro-resource-policies
|
||||
|
||||
S3SiteDeployPolicy:
|
||||
Type: AWS::IAM::ManagedPolicy
|
||||
Properties:
|
||||
Description: Allows listing buckets to be able to list objects in a bucket
|
||||
# ManagedPolicyName: Commented out because CloudFormation requires to rename when replacing custom-named resources
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
-
|
||||
Sid: AllowListingObjects
|
||||
Effect: Allow
|
||||
Action:
|
||||
- s3:ListBucket # To allow ListObjectsV2
|
||||
Resource: !Sub arn:aws:s3:::${WebStackName}*
|
||||
-
|
||||
Sid: AllowUpdatingObjects
|
||||
Effect: Allow
|
||||
Action:
|
||||
- s3:PutObject
|
||||
- s3:DeleteObject
|
||||
Resource: !Sub arn:aws:s3:::${WebStackName}*/*
|
||||
|
||||
CloudFrontInvalidationPolicy:
|
||||
Type: AWS::IAM::ManagedPolicy
|
||||
Properties:
|
||||
Description: Allows creating invalidations on CloudFront
|
||||
# ManagedPolicyName: Commented out because CloudFormation requires to rename when replacing custom-named resource
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
-
|
||||
Sid: AllowCloudFrontInvalidations
|
||||
Effect: Allow
|
||||
Action:
|
||||
- cloudfront:CreateInvalidation
|
||||
Resource: "*" # Does not support resource-level permissions https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cf-api-permissions-ref.html
|
||||
|
||||
StackExportReaderPolicy:
|
||||
Type: AWS::IAM::ManagedPolicy
|
||||
Properties:
|
||||
Description: Allows creating invalidations on CloudFront
|
||||
# ManagedPolicyName: Commented out because CloudFormation requires to rename when replacing custom-named resource
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
-
|
||||
Sid: AllowGettingBucketName
|
||||
Effect: Allow
|
||||
Action:
|
||||
- cloudformation:DescribeStacks
|
||||
Resource: !Sub arn:aws:cloudformation:*:${AWS::AccountId}:stack/${WebStackName}/*
|
||||
|
||||
Outputs:
|
||||
ResolveCertificateLambdaRoleArn:
|
||||
Description: The Amazon Resource Name (ARN) of the lambda for deploying certificates.
|
||||
Value: !GetAtt ResolveCertificateLambdaRole.Arn
|
||||
Export:
|
||||
Name: !Join [ ':', [ !Ref 'AWS::StackName', ResolveCertificateLambdaRoleArn ] ]
|
||||
|
||||
CertificateStackDeployRoleArn:
|
||||
Description: "GitHub secret: AWS_CERTIFICATE_STACK_DEPLOYMENT_ROLE_ARN"
|
||||
Value: !GetAtt CertificateStackDeployRole.Arn
|
||||
|
||||
DnsStackDeployRoleArn:
|
||||
Description: "GitHub secret: AWS_DNS_STACK_DEPLOYMENT_ROLE_ARN"
|
||||
Value: !GetAtt DnsStackDeployRole.Arn
|
||||
|
||||
IamStackDeployRoleArn:
|
||||
Description: "GitHub secret: AWS_IAM_STACK_DEPLOYMENT_ROLE_ARN"
|
||||
Value: !GetAtt IamStackDeployRole.Arn
|
||||
|
||||
WebStackDeployRoleArn:
|
||||
Description: "GitHub secret: AWS_WEB_STACK_DEPLOYMENT_ROLE_ARN"
|
||||
Value: !GetAtt WebStackDeployRole.Arn
|
||||
|
||||
S3SiteDeployRoleArn:
|
||||
Description: "GitHub secret: AWS_S3_SITE_DEPLOYMENT_ROLE_ARN"
|
||||
Value: !GetAtt S3SiteDeployRole.Arn
|
||||
|
||||
CloudFrontSiteDeployRoleArn:
|
||||
Description: "GitHub secret: AWS_CLOUDFRONT_SITE_DEPLOYMENT_ROLE_ARN"
|
||||
Value: !GetAtt CloudFrontSiteDeployRole.Arn
|
||||
@@ -1,36 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Parse parameters
|
||||
while [[ "$#" -gt 0 ]]; do case $1 in
|
||||
--user-profile) USER_PROFILE="$2"; shift;;
|
||||
--role-profile) ROLE_PROFILE="$2"; shift;;
|
||||
--role-arn) ROLE_ARN="$2"; shift;;
|
||||
--session) SESSION="$2";shift;;
|
||||
--region) REGION="$2";shift;;
|
||||
*) echo "Unknown parameter passed: $1"; exit 1;;
|
||||
esac; shift; done
|
||||
|
||||
# Verify parameters
|
||||
if [ -z "$USER_PROFILE" ]; then echo "User profile name is not set."; exit 1; fi;
|
||||
if [ -z "$ROLE_PROFILE" ]; then echo "Role profile name is not set."; exit 1; fi;
|
||||
if [ -z "$ROLE_ARN" ]; then echo "Role ARN is not set"; exit 1; fi;
|
||||
if [ -z "$SESSION" ]; then echo "Session name is not set."; exit 1; fi;
|
||||
if [ -z "$REGION" ]; then echo "Region is not set."; exit 1; fi;
|
||||
|
||||
creds=$(aws sts assume-role --role-arn $ROLE_ARN --role-session-name $SESSION --profile $USER_PROFILE)
|
||||
|
||||
aws_access_key_id=$(echo $creds | jq -r '.Credentials.AccessKeyId')
|
||||
echo ::add-mask::$aws_access_key_id
|
||||
aws_secret_access_key=$(echo $creds | jq -r '.Credentials.SecretAccessKey')
|
||||
echo ::add-mask::$aws_secret_access_key
|
||||
aws_session_token=$(echo $creds | jq -r '.Credentials.SessionToken')
|
||||
echo ::add-mask::$aws_session_token
|
||||
|
||||
aws configure --profile $ROLE_PROFILE set aws_access_key_id $aws_access_key_id
|
||||
aws configure --profile $ROLE_PROFILE set aws_secret_access_key $aws_secret_access_key
|
||||
aws configure --profile $ROLE_PROFILE set aws_session_token $aws_session_token
|
||||
aws configure --profile $ROLE_PROFILE set region $REGION
|
||||
|
||||
echo Profile $ROLE_PROFILE is created
|
||||
|
||||
bash "${BASH_SOURCE%/*}/mask-identity.sh" --profile $ROLE_PROFILE
|
||||
@@ -1,25 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Parse parameters
|
||||
while [[ "$#" -gt 0 ]]; do case $1 in
|
||||
--profile) PROFILE="$2"; shift;;
|
||||
--access-key-id) ACCESS_KEY_ID="$2"; shift;;
|
||||
--secret-access-key) SECRET_ACCESS_KEY="$2"; shift;;
|
||||
--region) REGION="$2";shift;;
|
||||
*) echo "Unknown parameter passed: $1"; exit 1;;
|
||||
esac; shift; done
|
||||
|
||||
# Verify parameters
|
||||
if [ -z "$PROFILE" ]; then echo "Profile name is not set."; exit 1; fi;
|
||||
echo $PROFILE
|
||||
if [ -z "$ACCESS_KEY_ID" ]; then echo "Access key ID is not set"; exit 1; fi;
|
||||
if [ -z "$SECRET_ACCESS_KEY" ]; then echo "Secret access key is not set."; exit 1; fi;
|
||||
if [ -z "$REGION" ]; then echo "Region is not set."; exit 1; fi;
|
||||
|
||||
aws configure --profile $PROFILE set aws_access_key_id $ACCESS_KEY_ID
|
||||
aws configure --profile $PROFILE set aws_secret_access_key $SECRET_ACCESS_KEY
|
||||
aws configure --profile $PROFILE set region $REGION
|
||||
|
||||
echo Profile $PROFILE is created
|
||||
|
||||
bash "${BASH_SOURCE%/*}/mask-identity.sh" --profile $PROFILE
|
||||
@@ -1,17 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Parse parameters
|
||||
while [[ "$#" -gt 0 ]]; do case $1 in
|
||||
--profile) PROFILE="$2";shift;;
|
||||
*) echo "Unknown parameter passed: $1"; exit 1;;
|
||||
esac; shift; done
|
||||
|
||||
# Verify parameters
|
||||
if [ -z "$PROFILE" ]; then echo "Profile name is not set."; exit 1; fi;
|
||||
|
||||
aws_identity=$(aws sts get-caller-identity --profile $PROFILE)
|
||||
echo ::add-mask::$(echo $aws_identity | jq -r '.Account')
|
||||
echo ::add-mask::$(echo $aws_identity | jq -r '.UserId')
|
||||
echo ::add-mask::$(echo $aws_identity | jq -r '.Arn')
|
||||
|
||||
echo Credentials are masked
|
||||
@@ -1,43 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Parse parameters
|
||||
while [[ "$#" -gt 0 ]]; do case $1 in
|
||||
--template-file) TEMPLATE_FILE="$2"; shift;;
|
||||
--stack-name) STACK_NAME="$2"; shift;;
|
||||
--profile) PROFILE="$2"; shift;;
|
||||
--capabilities) CAPABILITY_IAM="$2"; shift;;
|
||||
--role-arn) ROLE_ARN="$2";shift;;
|
||||
--session) SESSION="$2";shift;;
|
||||
--region) REGION="$2";shift;;
|
||||
*) echo "Unknown parameter passed: $1"; exit 1;;
|
||||
esac; shift; done
|
||||
|
||||
# Verify parameters
|
||||
if [ -z "$TEMPLATE_FILE" ]; then echo "Template file is not set."; exit 1; fi;
|
||||
if [ -z "$STACK_NAME" ]; then echo "Template file is not set."; exit 1; fi;
|
||||
if [ -z "$PROFILE" ]; then echo "Profile is not set."; exit 1; fi;
|
||||
if [ -z "$ROLE_ARN" ]; then echo "Role ARN is not set."; exit 1; fi;
|
||||
if [ -z "$SESSION" ]; then echo "Role session is not set."; exit 1; fi;
|
||||
|
||||
|
||||
echo Validating stack "$STACK_NAME"
|
||||
aws cloudformation validate-template \
|
||||
--template-body file://$TEMPLATE_FILE \
|
||||
--profile $PROFILE
|
||||
|
||||
ROLE_PROFILE=$STACK_NAME
|
||||
|
||||
echo Assuming role
|
||||
bash "${BASH_SOURCE%/*}/../configure/create-role-profile.sh" \
|
||||
--role-profile $ROLE_PROFILE --user-profile $PROFILE \
|
||||
--role-arn $ROLE_ARN \
|
||||
--session $SESSION \
|
||||
--region $REGION
|
||||
|
||||
echo Deploying stack "$TEMPLATE_FILE"
|
||||
aws cloudformation deploy \
|
||||
--template-file $TEMPLATE_FILE \
|
||||
--stack-name $STACK_NAME \
|
||||
${CAPABILITY_IAM:+ --capabilities $CAPABILITY_IAM} \
|
||||
--no-fail-on-empty-changeset \
|
||||
--profile $ROLE_PROFILE
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Parse parameters
|
||||
while [[ "$#" -gt 0 ]]; do case $1 in
|
||||
--folder) FOLDER="$2"; shift;;
|
||||
--web-stack-name) WEB_STACK_NAME="$2"; shift;;
|
||||
--web-stack-s3-name-output-name) WEB_STACK_S3_NAME_OUTPUT_NAME="$2"; shift;;
|
||||
--storage-class) STORAGE_CLASS="$2"; shift;;
|
||||
--profile) PROFILE="$2"; shift;;
|
||||
--role-arn) ROLE_ARN="$2";shift;;
|
||||
--session) SESSION="$2";shift;;
|
||||
--region) REGION="$2";shift;;
|
||||
*) echo "Unknown parameter passed: $1"; exit 1;;
|
||||
esac; shift; done
|
||||
|
||||
# Verify parameters
|
||||
if [ -z "$FOLDER" ]; then echo "Folder is not set."; exit 1; fi;
|
||||
if [ -z "$PROFILE" ]; then echo "Profile is not set."; exit 1; fi;
|
||||
if [ -z "$ROLE_ARN" ]; then echo "Role ARN is not set."; exit 1; fi;
|
||||
if [ -z "$SESSION" ]; then echo "Role session is not set."; exit 1; fi;
|
||||
if [ -z "$WEB_STACK_NAME" ]; then echo "Web stack name is not set."; exit 1; fi;
|
||||
if [ -z "$WEB_STACK_S3_NAME_OUTPUT_NAME" ]; then echo "S3 name output name is not set."; exit 1; fi;
|
||||
if [ -z "$STORAGE_CLASS" ]; then echo "S3 object storage class is not set."; exit 1; fi;
|
||||
|
||||
echo Assuming role
|
||||
ROLE_PROFILE=deploy-s3
|
||||
bash "${BASH_SOURCE%/*}/../configure/create-role-profile.sh" \
|
||||
--role-profile $ROLE_PROFILE --user-profile $PROFILE \
|
||||
--role-arn $ROLE_ARN \
|
||||
--session $SESSION \
|
||||
--region $REGION
|
||||
|
||||
echo Getting S3 bucket name from stack "$WEB_STACK_NAME" with output "$WEB_STACK_S3_NAME_OUTPUT_NAME"
|
||||
S3_BUCKET_NAME=$(aws cloudformation describe-stacks \
|
||||
--stack-name $WEB_STACK_NAME \
|
||||
--query "Stacks[0].Outputs[?OutputKey=='$WEB_STACK_S3_NAME_OUTPUT_NAME'].OutputValue" \
|
||||
--output text \
|
||||
--profile $ROLE_PROFILE)
|
||||
if [ -z "$S3_BUCKET_NAME" ]; then echo "Could not read S3 bucket name"; exit 1; fi;
|
||||
echo ::add-mask::$S3_BUCKET_NAME # Just being extra cautious
|
||||
|
||||
echo Syncing folder to S3
|
||||
|
||||
aws s3 sync $FOLDER s3://$S3_BUCKET_NAME \
|
||||
--storage-class $STORAGE_CLASS \
|
||||
--no-progress --follow-symlinks --delete \
|
||||
--profile $ROLE_PROFILE
|
||||
@@ -1,45 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Parse parameters
|
||||
while [[ "$#" -gt 0 ]]; do case $1 in
|
||||
--paths) PATHS="$2"; shift;;
|
||||
--web-stack-name) WEB_STACK_NAME="$2"; shift;;
|
||||
--web-stack-cloudfront-arn-output-name) WEB_STACK_CLOUDFRONT_ARN_OUTPUT_NAME="$2"; shift;;
|
||||
--profile) PROFILE="$2"; shift;;
|
||||
--role-arn) ROLE_ARN="$2";shift;;
|
||||
--session) SESSION="$2";shift;;
|
||||
--region) REGION="$2";shift;;
|
||||
*) echo "Unknown parameter passed: $1"; exit 1;;
|
||||
esac; shift; done
|
||||
|
||||
# Verify parameters
|
||||
if [ -z "$PATHS" ]; then echo "Paths is not set."; exit 1; fi;
|
||||
if [ -z "$PROFILE" ]; then echo "Profile is not set."; exit 1; fi;
|
||||
if [ -z "$ROLE_ARN" ]; then echo "Role ARN is not set."; exit 1; fi;
|
||||
if [ -z "$SESSION" ]; then echo "Role session is not set."; exit 1; fi;
|
||||
if [ -z "$WEB_STACK_NAME" ]; then echo "Web stack name is not set."; exit 1; fi;
|
||||
if [ -z "$WEB_STACK_CLOUDFRONT_ARN_OUTPUT_NAME" ]; then echo "CloudFront ARN output name is not set."; exit 1; fi;
|
||||
|
||||
|
||||
echo Assuming role
|
||||
ROLE_PROFILE=invalidate-cloudfront
|
||||
bash "${BASH_SOURCE%/*}/../configure/create-role-profile.sh" \
|
||||
--role-profile $ROLE_PROFILE --user-profile $PROFILE \
|
||||
--role-arn $ROLE_ARN \
|
||||
--session $SESSION \
|
||||
--region $REGION
|
||||
|
||||
echo Getting CloudFront ARN from stack "$WEB_STACK_NAME" with output "$WEB_STACK_CLOUDFRONT_ARN_OUTPUT_NAME"
|
||||
CLOUDFRONT_ARN=$(aws cloudformation describe-stacks \
|
||||
--stack-name $WEB_STACK_NAME \
|
||||
--query "Stacks[0].Outputs[?OutputKey=='$WEB_STACK_CLOUDFRONT_ARN_OUTPUT_NAME'].OutputValue" \
|
||||
--output text \
|
||||
--profile $ROLE_PROFILE)
|
||||
if [ -z "$CLOUDFRONT_ARN" ]; then echo "Could not read CloudFront ARN"; exit 1; fi;
|
||||
echo :add-mask::$CLOUDFRONT_ARN
|
||||
|
||||
echo Syncing folder to S3
|
||||
aws cloudfront create-invalidation \
|
||||
--paths $PATHS \
|
||||
--distribution-id $CLOUDFRONT_ARN \
|
||||
--profile $ROLE_PROFILE
|
||||
@@ -1,138 +0,0 @@
|
||||
AWSTemplateFormatVersion: '2010-09-09'
|
||||
|
||||
Description: |-
|
||||
> Creates an S3 bucket configured for hosting a static webpage.
|
||||
> Creates CloudFront distribution that has access to read the S3 bucket.
|
||||
|
||||
Parameters:
|
||||
|
||||
RootDomainName:
|
||||
Type: String
|
||||
Default: privacy.sexy
|
||||
Description: The root DNS name of the website e.g. privacy.sexy
|
||||
AllowedPattern: (?!-)[a-zA-Z0-9-.]{1,63}(?<!-)
|
||||
ConstraintDescription: Must be a valid root domain name
|
||||
|
||||
CertificateStackName:
|
||||
Type: String
|
||||
Default: privacysexy-certificate-stack
|
||||
Description: Name of the certificate stack.
|
||||
|
||||
DnsStackName:
|
||||
Type: String
|
||||
Default: privacysexy-dns-stack
|
||||
Description: Name of the certificate stack.
|
||||
|
||||
PriceClass:
|
||||
Type: String
|
||||
Description: The CloudFront distribution price class
|
||||
Default: 'PriceClass_100'
|
||||
AllowedValues:
|
||||
- 'PriceClass_100'
|
||||
- 'PriceClass_200'
|
||||
- 'PriceClass_All'
|
||||
|
||||
Resources:
|
||||
|
||||
S3Bucket:
|
||||
Type: AWS::S3::Bucket
|
||||
Properties:
|
||||
BucketName: !Sub ${AWS::StackName}-${RootDomainName} # Must have stack name for IAM to allow
|
||||
WebsiteConfiguration:
|
||||
IndexDocument: index.html
|
||||
Tags:
|
||||
-
|
||||
Key: Application
|
||||
Value: privacy.sexy
|
||||
|
||||
S3BucketPolicy:
|
||||
Type: AWS::S3::BucketPolicy
|
||||
Properties:
|
||||
Bucket: !Ref S3Bucket
|
||||
PolicyDocument: # Only used for CloudFront as it's the only way, otherwise use IAM roles in IAM stack.
|
||||
Statement:
|
||||
-
|
||||
Sid: AllowCloudFrontRead
|
||||
Action: s3:GetObject
|
||||
Effect: Allow
|
||||
Principal:
|
||||
CanonicalUser: !GetAtt CloudFrontOriginAccessIdentity.S3CanonicalUserId
|
||||
Resource: !Join ['', ['arn:aws:s3:::', !Ref S3Bucket, /*]]
|
||||
|
||||
CloudFrontOriginAccessIdentity:
|
||||
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
|
||||
Properties:
|
||||
CloudFrontOriginAccessIdentityConfig:
|
||||
Comment: !Sub 'CloudFront OAI for ${S3Bucket}'
|
||||
|
||||
CloudFrontDistribution:
|
||||
Type: AWS::CloudFront::Distribution
|
||||
Properties:
|
||||
DistributionConfig:
|
||||
Comment: Cloudfront Distribution pointing to S3 bucket
|
||||
Origins:
|
||||
-
|
||||
DomainName: !GetAtt S3Bucket.DomainName
|
||||
Id: S3Origin
|
||||
S3OriginConfig:
|
||||
OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}"
|
||||
Enabled: true
|
||||
HttpVersion: 'http2'
|
||||
DefaultRootObject: index.html
|
||||
Aliases:
|
||||
- !Ref RootDomainName
|
||||
- !Sub 'www.${RootDomainName}'
|
||||
DefaultCacheBehavior:
|
||||
AllowedMethods:
|
||||
- GET
|
||||
- HEAD
|
||||
Compress: true
|
||||
TargetOriginId: S3Origin
|
||||
ForwardedValues:
|
||||
QueryString: true
|
||||
Cookies:
|
||||
Forward: none
|
||||
ViewerProtocolPolicy: redirect-to-https
|
||||
PriceClass: !Ref PriceClass
|
||||
ViewerCertificate:
|
||||
AcmCertificateArn:
|
||||
# Certificate must be validated before it can be used here
|
||||
Fn::ImportValue: !Join [':', [!Ref CertificateStackName, CertificateArn]]
|
||||
SslSupportMethod: sni-only
|
||||
MinimumProtocolVersion: TLSv1.1_2016
|
||||
Tags:
|
||||
-
|
||||
Key: Application
|
||||
Value: privacy.sexy
|
||||
|
||||
CloudFrontDNSRecords:
|
||||
Type: AWS::Route53::RecordSetGroup
|
||||
Properties:
|
||||
HostedZoneId:
|
||||
Fn::ImportValue: !Join [':', [!Ref DnsStackName, DNSHostedZoneId]]
|
||||
RecordSets:
|
||||
-
|
||||
Name: !Ref RootDomainName
|
||||
Type: A
|
||||
AliasTarget:
|
||||
DNSName: !GetAtt CloudFrontDistribution.DomainName
|
||||
EvaluateTargetHealth: false
|
||||
HostedZoneId: Z2FDTNDATAQYW2 # Static CloudFront distribution zone https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-aliastarget.html#cfn-route53-aliastarget-hostedzoneid
|
||||
-
|
||||
Name: !Join ['', ['www.', !Ref RootDomainName]]
|
||||
Type: A
|
||||
AliasTarget:
|
||||
DNSName: !GetAtt CloudFrontDistribution.DomainName
|
||||
EvaluateTargetHealth: false
|
||||
HostedZoneId: Z2FDTNDATAQYW2 # Static CloudFront distribution zone https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-aliastarget.html#cfn-route53-aliastarget-hostedzoneid
|
||||
Outputs:
|
||||
|
||||
CloudFrontDistributionArn: # Used by deployment script to be able to deploy to right S3 bucket
|
||||
Description: Tthe Amazon Resource Name (ARN) of the CloudFront distribution.
|
||||
Value: !Ref CloudFrontDistribution
|
||||
|
||||
S3BucketName: # Used by deployment script to be able to deploy to right S3 bucket
|
||||
Description: Name of the S3 bucket.
|
||||
Value: !Ref S3Bucket
|
||||
|
||||
|
||||
5
babel.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset',
|
||||
],
|
||||
};
|
||||
5
build/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# build
|
||||
|
||||
- These are the file that are used by electron.
|
||||
- Logos are created by from the [PNG icon](./../public/icon.png)
|
||||
- by running `npx electron-icon-builder --input=./public/icon.png --output=build --flatten`
|
||||
BIN
build/icons/1024x1024.png
Normal file
|
After Width: | Height: | Size: 225 KiB |
BIN
build/icons/128x128.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
BIN
build/icons/16x16.png
Normal file
|
After Width: | Height: | Size: 740 B |
BIN
build/icons/24x24.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
build/icons/256x256.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
build/icons/32x32.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
build/icons/48x48.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
build/icons/512x512.png
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
build/icons/64x64.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
build/icons/icon.icns
Normal file
BIN
build/icons/icon.ico
Normal file
|
After Width: | Height: | Size: 353 KiB |
3
cypress.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"pluginsFile": "tests/e2e/plugins/index.js"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<mxfile host="www.draw.io" modified="2019-12-27T03:04:27.829Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36" etag="O-1eaon4mqUmgvki0auB" version="12.4.3" pages="1"><diagram id="rhL8jzEM8kVVyiS98U7u" name="Page-1">3Zpdk6I4FIZ/jZdakPDlpa3tzlTNbnVVV83OzE1XhACZAUKF2Or8+k0wCBhau1f8GrpayUkC5HlzTg7IAE7T9V8M5fHfNMDJABjBegBnAwA8YIpPadhsDS50t4aIkWBrMmvDM/mNldFQ1iUJcNFqyClNOMnbRp9mGfZ5y4YYo6t2s5Am7bPmKMKa4dlHiW79lwQ8VsOyjdr+CZMors5sGqomRVVjZShiFNBVwwQfB3DKKOXbvXQ9xYlkV3HZ9pu/Ubu7MIYz/p4OD0/efJxMXmZfs6kd/vj2Txp+HlrVxfFNNWIcCACqSBmPaUQzlDzW1gdGl1mA5WENUarbfKE0F0ZTGH9izjdKTbTkVJhiniaqFq8J/ya7j2xV+t6oma3VkcvCpipknG0anWTxe7Ou7laWqn4FZ/QXntKEsnJ8cFxuomY7cjncN4kqU0GXzMcHMFYzE7EI8wPtwE534S+YplhcqejHcII4eW1fB1IzN9q1q8UVO0rfj2gNrqL1TreWarWI96AbPFG3suuEMbRpNMgpyXjROPKTNIgGKnZC5Zsqctp77n24NTDtvQmzPX09fXbjOGFGwatGj0bsMEbAfmf4uONpaF0zfKjjvqJkqc70xHAhxirOTTNtIrRlXsWE4+cclRhWIlNoSxqSJGkwDmzsBVYXfQ8soOPIHjTj1TyrrgwzjteHxdDhqQ6O23Yf5U2res2H1coeN9Z7xzgTbehc07XMlmu907PMtmeBm3AtcCHX+n8RftwO2iZsBe2j7YHrnj/IQ+9eUsSbmlCnpgwnRQ+gxepJnifE7yNUtwKvFrpDW/51ieGUmzpCw77ddiKdFMXtdhTf3Yw1wzjoCOPu2cK4fS/Oc9P3V/AeEiSoOd2Mpoj0mxotzCAIO7mbhgvH+Ayp0XjPqca6UwGrw6nsczmVpYH+nIUMCSJLny8Z7hV46PnY97uALzzbso0zAHf3clGnA7h3ySjmaMDxK1aZzRugzY+DDrHTDTpwxwvD6GeF8PbYujpbtwMtOBdaV0PLcE4Lwqk6+F3jhR0L8EXxenqoeMw44ffIdj8uXB3uWIPLY4ZRQLLoD8B79dBg6ll8Kn9e6TfsLpDvBbALLoCWZQf9wBXJSRuuYelw7ZHZgRecC6+er4ldEhy7R7pVxMA2R+Obg2xrkAuO+KEU7R18e6C15+xm9ZTjiqjOk2X1MbOc47DMrqej52Olp02o+YDDSGhE/NsDZ+pLymXBVWPoBjfaiNFfG9rtMdMXCg1SEaNc7pK0fJ+giUTCEHyTSUKiTNi4fIizs35BC5w8yYRfTlw4W1DOaSoaJLLiAfm/olKAVjokN9GkPNmkyLfvPcg0CFWFkKylZA/qemYx5/KFiYkkAeZ+kFkj4tMsJEJaNvLFGcFcrHxIfEm7iDlz4UK0GKIsGC6Y+JQmW6Ykc+i4L1+X+GfxIpuINMUb5VXG1+t9r60Jb1/yMQPQ16771x1+WPchCugC79QHnvfyjIqiR91NcGPC6yvx/QtvHhV+ka3Ep5B1Lf7FnlgYpFk+3Sp6Uhq4+zkqBCNdbQh1tStb/2rrucT9q20cVTukLMLZsMBU/rI/d8Stwjwn5fPTYkhzTlLyu0wKenR0WN0O7MTXpbc6pLc+LL0o1m/WbX8JrV9PhI//AQ==</diagram></mxfile>
|
||||
BIN
docs/app-ddd.png
|
Before Width: | Height: | Size: 26 KiB |
44
docs/application.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Application
|
||||
|
||||
- It's mainly responsible for
|
||||
- creating and event based [application state](#application-state)
|
||||
- [parsing](#parsing) and [compiling](#compiling) [application data](#application-data)
|
||||
- Consumed by [presentation layer](./presentation.md)
|
||||
|
||||
## Structure
|
||||
|
||||
- [`/src/` **`application/`**](./../src/application/): Contains all application related code.
|
||||
- [**`collections/`**](./../src/application/collections/): Holds [collection files](./collection-files.md)
|
||||
- [**`Common/`**](./../src/application/Common/): Contains common functionality that is shared in application layer.
|
||||
- `..`: other classes are categorized using folders-by-feature structure
|
||||
|
||||
## Application state
|
||||
|
||||
- [ApplicationContext.ts](./../src/application/Context/ApplicationContext.ts) holds the [CategoryCollectionState](./../src/application/Context/State/CategoryCollectionState.ts) for each OS
|
||||
- Uses [state pattern](https://en.wikipedia.org/wiki/State_pattern)
|
||||
- Same instance is shared throughout the application to ensure consistent state
|
||||
- 📖 See [Application State | Presentation layer](./presentation.md#application-state) to read more about how the state should be managed by the presentation layer.
|
||||
- 📖 See [ApplicationContext.ts](./../src/application/Context/ApplicationContext.ts) to start diving into the state code.
|
||||
|
||||
## Application data
|
||||
|
||||
- Compiled to [`Application`](./../src/domain/Application.ts) domain object.
|
||||
- The scripts are defined and controlled in different data files per OS
|
||||
- Enables [data-driven programming](https://en.wikipedia.org/wiki/Data-driven_programming) and easier contributions
|
||||
- Application data is defined in collection files and
|
||||
- 📖 See [Application data | Presentation layer](./presentation.md#application-data) to read how the application data is read by the presentation layer.
|
||||
- 📖 See [collection files documentation](./collection-files.md) to read more about how the data files are structured/defined and see [collection yaml files](./../src/application/collections/) to directly check the code.
|
||||
|
||||
## Parsing
|
||||
|
||||
- Application data is parsed to domain object [`Application.ts`](./../src/domain/Application.ts)
|
||||
- Steps
|
||||
1. (Compile time) Load application data from [collection yaml files](./../src/application/collections/) using webpack loader
|
||||
2. (Runtime) Parse and compile application and make it available to presentation layer by [`ApplicationFactory.ts`](./../src/application/ApplicationFactory.ts)
|
||||
|
||||
### Compiling
|
||||
|
||||
- Parsing the application files includes compiling scripts using [collection file defined functions](./collection-files.md#function)
|
||||
- To extend the syntax:
|
||||
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/Script/Compiler/Expressions/Parser/CompositeExpressionParser.ts)
|
||||
|
Before Width: | Height: | Size: 236 KiB |
@@ -1 +0,0 @@
|
||||
<mxfile host="www.draw.io" modified="2019-12-30T13:07:22.931Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36" etag="vfXOAJJrIONaUEloGBPR" version="12.4.7" type="device"><diagram id="ymF_tBZ9P2_Wfw9L8arg" name="Page-1">5Vpbb9s2FP41AbYHC7zp9hjHdVqsGwpkQNu9FIxEy2xlUaWo2N6v36FEOZLlXNw6S7IpQUwd3j9+/M4hnTN6sdpcal4uf1epyM8ISjdndHZGSOQT+GsN29YwIRFqLZmWaWvDt4Yr+bdwxq5YLVNRDQoapXIjy6ExUUUhEjOwca3VelhsofJhryXPxMhwlfB8bP0oU7Ps5oVu7W+FzJZdzxi5nBXvCjtDteSpWvdM9M0ZvdBKmTa12lyI3ILX4dLWm9+RuxuYFoV5TAWx2swv/wy+49kff33Kok8f39/8NnHLc8Pz2k14JspcbStbsVhoXhldJ6bWwk3CbDtktKqLVNjG0RmdKm2WKlMFz98rVYIRg/GrMGbr1pTXRoFpaVa5y015tWzqdy8fuDFCF42FIGsdz9FNu1K1TsQ9E2OOK1xnwtxTDvttQZEOeOAgvBRqJYzeQgHH6AnyCGVBW8mRmro2tMi5kTdD5nBHwGzX1K71D0rCtHZN05B6FB4/ZiGNCQoHneAgxF7Mho22MLh2+mu/17QfIA8F8e0zbBrHyMOxH0IyojgkZNhLC+LDvezNWC0WlRjUgEQP01tTw9QjWEtHrJ3WMk+rRgdSoGqQw5pPrzWkMptqSQ3Za3FtR1iWuUxgrVTxH6V1eDSrEQuGhCPsNKxm2KMIIYZY5Ef0dJwOgsALaLij9HBPYqC71yN87B/J6adnMRux+FKat7Ul6HliuVmNyAk+pLRJuWrcVp92N0Ib4HR+nsvMcs1Yuu6s7/m1yD+oSjacp7NrZYxaQYHcZkx58i1riH+hcqWbvuiieaBI09l5Vbbu1e4K3r0s5MZSferGM1saY/3yucWKzJO0YJ4Ez7yQsKW0l0CPZJ5yw+HD2iv7qYou6WPiMiaVSiTPJ5k0y/p6gknklUUGHS1knndjLFRhMViowlw5iA44RWeyQIjNY/YCCXwvYOj2YUNikcA59PVtPAADbG3LfizQGQ9tlgGZjmWOP2LOuwJeJEArGhHkyfKFOezHKhE4IhoPEacnEqKYgl7c6QMp6IUfhjTwGWUhi+kPelofeywaNs380KMEiERiGuGXKEXBiFAXuarTuVZuTH0eqdrkshAXu4gbuV3YEw/4mdv+p5nmqRSDvJj5sznp5c2kFokTpsLycm+jQx3/nKKpD3aIR9U3cUimduxEj9G9w3LJ3VsCoxJ6yP5GZ9qtgclIdw6IYifWq01mz0YeX1fM06Jl0rvEjmcKr21qWCqx6C8a9J1E9+awG1zaww1abXA7gQAepDAdi154QPPCp5K8cMTQK3pyZgbonNLwOGaSMMQ4+N8ws6I2b+dJcNtae7C108tyXlUuDf5eJi59El5SL9p3xpH/vLyMRryciZvXH7eRB+O2QqwnW8H1xPImr128Og9ggeY90wTFvfDtTikb0fvUUZ0PJ5z+Q/d5FI95hA7wCD0Rj+IRj8q6qaXF91pUNgyQ1fhguxIQO6TNpVhz51RZ9J4j8IOV0dtProvm5bN98fzudbbpZ862D+nCg0dht/MePAqz4wJQOApTTIcyc6KjMEN0cLLA+xEo82gckBgHPmE4+tEINACZJHfGuYwhj4Uh8eMwBK8eBi8uGO2ufnt74fULKn1QUMVKfZUTbPnaqugXmGO5/VKtZC6295+BD8Qyu1GfQDztsexY9SQH1JM8lXpiPKLMmDPQjiwrC9d6KY24KnmjL2sIbvbiqWGEt1iIIEkORXhpGF8j9ATeiu0Dvne5hSPidRrVw5ziMeb0yTAff3cwjshfE+bB/ZhD/PnMgI+vvdmrBjxi9wJOGX1mwMc3tPg1A473g+ARw8eH/H8X8PHFZhfyViUvBsAH32v7zSkcMhvgzm14ll3/AkODX+ge9VK/2qT1hMhCOlm7udg6oS3XtdVF1e3ll9Ir9xVROwSYUjuKttCICT97+zCnjEVH3otNLzD1X+7tw8EY6afvxXYL82TXCqA9h/zriW4W7Al597V/GzXf/vMEffMP</diagram></mxfile>
|
||||
19
docs/ci-cd.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Pipelines
|
||||
|
||||
Pipelines are found under [`.github/workflows`](./../.github/workflows).
|
||||
|
||||
## Pipeline types
|
||||
|
||||
They are categorized based on their type:
|
||||
|
||||
- `tests`: Different types of tests to verify functionality.
|
||||
- `checks`: Other controls such as vulnerability scans or styling checks.
|
||||
- `release`: Pipelines used for release of deployment such as building and testing.
|
||||
|
||||
## Naming conventions
|
||||
|
||||
Pipeline files are named using: **`<type>.<name>.yaml`**.
|
||||
|
||||
**`type`**: Sub-folders do not work for GitHub workflows so that's why `<type>.` prefix is used. See also [pipeline types](#pipeline-types).
|
||||
|
||||
**`name`**: Pipeline themselves are named using kebab case. It allows for easier URL references for their status badges. E.g. file name `tests.unit.yaml`, pipeline name: `name: unit-tests`
|
||||
BIN
docs/ci-cd.png
|
Before Width: | Height: | Size: 48 KiB |
173
docs/collection-files.md
Normal file
@@ -0,0 +1,173 @@
|
||||
# Collection 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/)
|
||||
- 💡 Best practices
|
||||
- If you repeat yourself, try to utilize [YAML-defined functions](#Function)
|
||||
- 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)
|
||||
|
||||
## Objects
|
||||
|
||||
### `Collection`
|
||||
|
||||
- A collection simply defines:
|
||||
- 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
|
||||
|
||||
- `os:` *`string`* (**required**)
|
||||
- Operating system that the [Collection](#collection) is written for.
|
||||
- 📖 See [OperatingSystem.ts](./../src/domain/OperatingSystem.ts) enumeration for allowed values.
|
||||
- `actions: [` ***[`Category`](#Category)*** `, ... ]` **(required)**
|
||||
- Each [category](#category) is rendered as different cards in card presentation.
|
||||
- ❗ A [Collection](#collection) must consist of at least one category.
|
||||
- `functions: [` ***[`Function`](#Function)*** `, ... ]`
|
||||
- Functions are optionally defined to re-use the same code throughout different scripts.
|
||||
- `scripting:` ***[`ScriptingDefinition`](#ScriptingDefinition)*** **(required)**
|
||||
- Defines the scripting language that the code of other action uses.
|
||||
|
||||
### `Category`
|
||||
|
||||
- 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.
|
||||
|
||||
#### `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.
|
||||
- Children can be combination of scripts and subcategories.
|
||||
|
||||
### `Script`
|
||||
|
||||
- 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.
|
||||
|
||||
#### `Script` syntax
|
||||
|
||||
- `name`: *`string`* (**required**)
|
||||
- Name of the script
|
||||
- ❗ Must be unique throughout the [Collection](#collection)
|
||||
- E.g. `Disable targeted ads`
|
||||
- `code`: *`string`* (may be **required**)
|
||||
- Batch file commands that will be executed
|
||||
- 💡 If defined, best practice to also define `revertCode`
|
||||
- ❗ If not defined `call` must be defined, do not define if `call` is defined.
|
||||
- `revertCode`: `string`
|
||||
- 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`
|
||||
- then `revertCode` should be doing `setx POWERSHELL_TELEMETRY_OPTOUT 0`
|
||||
- ❗ Do not define if `call` is defined.
|
||||
- `call`: ***[`FunctionCall`](#FunctionCall)*** | `[` ***[`FunctionCall`](#FunctionCall)*** `, ... ]` (may be **required**)
|
||||
- A shared function or sequence of functions to call (called in order)
|
||||
- ❗ If not defined `code` must be defined
|
||||
- `docs`: *`string`* | `[`*`string`*`, ... ]`
|
||||
- Single documentation URL or list of URLs for those who wants to learn more about the script
|
||||
- E.g. `https://docs.microsoft.com/en-us/windows-server/`
|
||||
- `recommend`: `"standard"` | `"strict"` | `undefined` (default)
|
||||
- If not defined then the script will not be recommended
|
||||
- If defined it can be either
|
||||
- `standard`: Only non-breaking scripts without limiting OS functionality
|
||||
- `strict`: Scripts that can break certain functionality in favor of privacy and security
|
||||
|
||||
### `FunctionCall`
|
||||
|
||||
- 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
|
||||
|
||||
- `function`: *`string`* (**required**)
|
||||
- Name of the function to call.
|
||||
- ❗ Function with same name must defined in `functions` property of [Collection](#collection)
|
||||
- `parameters`: `[ parameterName:` *`parameterValue`*`, ... ]`
|
||||
- Defines key value dictionary for each parameter and its value
|
||||
- E.g.
|
||||
|
||||
```yaml
|
||||
parameters:
|
||||
userDefinedParameterName: parameterValue
|
||||
# ...
|
||||
appName: Microsoft.WindowsFeedbackHub
|
||||
```
|
||||
|
||||
- 💡 [Expressions (templating)](./templating.md#expressions) can be used as parameter value
|
||||
|
||||
### `Function`
|
||||
|
||||
- Functions allow re-usable code throughout the defined scripts.
|
||||
- Functions are templates compiled by privacy.sexy and uses special expression expressions.
|
||||
- A function can be of two different types (just like [scripts](#script)):
|
||||
1. Inline function: a function with an inline code.
|
||||
- Must define `code` property and optionally `revertCode` but not `call`.
|
||||
2. Caller function: a function that calls other functions.
|
||||
- Must define `call` property but not `code` or `revertCode`.
|
||||
- 👀 Read more on [Templating](./templating.md) for function expressions and [example usages](./templating.md#parameter-substitution).
|
||||
|
||||
#### `Function` syntax
|
||||
|
||||
- `name`: *`string`* (**required**)
|
||||
- Name of the function that scripts will use.
|
||||
- Convention is to use camelCase, and be verbs.
|
||||
- E.g. `uninstallStoreApp`
|
||||
- ❗ Function names must be unique
|
||||
- `parameters`: `[` ***[`FunctionParameter`](#FunctionParameter)*** `, ... ]`
|
||||
- List of parameters that function code refers to.
|
||||
- ❗ Must be defined to be able use in [`FunctionCall`](#functioncall) or [expressions (templating)](./templating.md#expressions)
|
||||
`code`: *`string`* (**required** if `call` is undefined)
|
||||
- Batch file commands that will be executed
|
||||
- 💡 [Expressions (templating)](./templating.md#expressions) can be used in its value
|
||||
- 💡 If defined, best practice to also define `revertCode`
|
||||
- ❗ If not defined `call` must be defined
|
||||
- `revertCode`: *`string`*
|
||||
- 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`
|
||||
- then `revertCode` should be doing `setx POWERSHELL_TELEMETRY_OPTOUT 0`
|
||||
- 💡 [Expressions (templating)](./templating.md#expressions) can be used in code
|
||||
- `call`: ***[`FunctionCall`](#FunctionCall)*** | `[` ***[`FunctionCall`](#FunctionCall)*** `, ... ]` (may be **required**)
|
||||
- A shared function or sequence of functions to call (called in order)
|
||||
- The parameter values that are sent can use [expressions (templating)](./templating.md#expressions)
|
||||
- ❗ If not defined `code` must be defined
|
||||
|
||||
### `FunctionParameter`
|
||||
|
||||
- Defines a parameter that function requires optionally or mandatory.
|
||||
- Its arguments are provided by a [Script](#script) through a [FunctionCall](#FunctionCall).
|
||||
|
||||
#### `FunctionParameter` syntax
|
||||
|
||||
- `name`: *`string`* (**required**)
|
||||
- Name of the parameters that the function has.
|
||||
- Parameter names must be defined to be used in [expressions (templating)](./templating.md#expressions).
|
||||
- ❗ Parameter names must be unique and include alphanumeric characters only.
|
||||
- `optional`: *`boolean`* (default: `false`)
|
||||
- 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;
|
||||
- Otherwise it throws.
|
||||
- 💡 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.
|
||||
- 💡 Can be used in conjunction with [`with` expression](./templating.md#with).
|
||||
|
||||
### `ScriptingDefinition`
|
||||
|
||||
- Defines global properties for scripting that's used throughout its parent [Collection](#collection).
|
||||
|
||||
#### `ScriptingDefinition` syntax
|
||||
|
||||
- `language:` *`string`* (**required**)
|
||||
- 📖 See [ScriptingLanguage.ts](./../src/domain/ScriptingLanguage.ts) enumeration for allowed values.
|
||||
- `startCode:` *`string`* (**required**)
|
||||
- Code that'll be inserted on top of user created script.
|
||||
- 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**)
|
||||
- Code that'll be inserted at the end of user created script.
|
||||
- Global variables such as `$homepage`, `$version`, `$date` can be used using [parameter substitution](./templating.md#parameter-substitution) code syntax such as `Welcome to {{ $homepage }}!`
|
||||
72
docs/presentation.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# Presentation layer
|
||||
|
||||
- Consists of Vue.js components and other UI-related code.
|
||||
- Desktop application is created using [Electron](https://www.electronjs.org/).
|
||||
- Event driven as in components simply listens to events from the state and act accordingly.
|
||||
|
||||
## Structure
|
||||
|
||||
- [`/src/` **`presentation/`**](./../src/presentation/): Contains all presentation related code including Vue and Electron configurations
|
||||
- [**`bootstrapping/`**](./../src/presentation/bootstrapping/): Registers Vue global objects including components and plugins.
|
||||
- [**`components/`**](./../src/presentation/components/): Contains all Vue components and their helper classes.
|
||||
- [**`Shared/`**](./../src/presentation/components/Shared): Contains Vue components and component helpers that are shared across other components.
|
||||
- [**`assets/`**](./../src/presentation/assets/styles/): Contains assets that will be processed by webpack.
|
||||
- [**`fonts/`**](./../src/presentation/assets/fonts/): Contains fonts
|
||||
- [**`styles/`**](./../src/presentation/assets/styles/): Contains shared styles used throughout different components.
|
||||
- [**`components/`**](./../src/presentation/assets/styles/components): Contains styles that are reusable and tightly coupled a Vue/HTML component.
|
||||
- [**`vendors-extensions/`**](./../src/presentation/assets/styles/third-party-extensions): Contains styles that override third-party components used.
|
||||
- [**`main.scss`**](./../src/presentation/assets/styles/main.scss): Primary Sass file, passes along all other styles, should be the only file used from other components.
|
||||
- [**`main.ts`**](./../src/presentation/main.ts): Application entry point that mounts and starts Vue application.
|
||||
- [**`electron/`**](./../src/presentation/electron/): Electron configuration for the desktop application.
|
||||
- [**`main.ts`**](./../src/presentation/main.ts): Main process of Electron, started as first thing when app starts.
|
||||
- [**`/public/`**](./../public/): Contains static assets that will directly be copied and not go through webpack.
|
||||
- [**`/vue.config.js`**](./../vue.config.js): Global Vue CLI configurations loaded by `@vue/cli-service`
|
||||
- [**`/postcss.config.js`**](./../postcss.config.js): PostCSS configurations that are used by Vue CLI internally
|
||||
- [**`/babel.config.js`**](./../babel.config.js): Babel configurations for polyfills used by `@vue/cli-plugin-babel`
|
||||
|
||||
## Application data
|
||||
|
||||
- Components and should use [ApplicationFactory](./../src/application/ApplicationFactory.ts) singleton to reach the application domain.
|
||||
- [Application.ts](../src/domain/Application.ts) domain model is the stateless application representation including
|
||||
- available scripts, collections as defined in [collection files](./collection-files.md)
|
||||
- package information as defined in [`package.json`](./../package.json)
|
||||
- 📖 See [Application data | Application layer](./presentation.md#application-data) where application data is parsed and compiled.
|
||||
|
||||
## Application state
|
||||
|
||||
- Stateful components mutate or/and react to state changes in [ApplicationContext](./../src/application/Context/ApplicationContext.ts).
|
||||
- Stateless components that does not handle state extends `Vue`
|
||||
- Stateful components that depends on the collection state such as user selection, search queries and more extends [`StatefulVue`](./../src/presentation/components/Shared/StatefulVue.ts)
|
||||
- The single source of truth is a singleton of the state created and made available to presentation layer by [`StatefulVue`](./../src/presentation/components/Shared/StatefulVue.ts)
|
||||
- `StatefulVue` includes abstract `handleCollectionState` that is fired once the component is loaded and also each time [collection](./collection-files.md) is changed.
|
||||
- Do not forget to subscribe from events when component is destroyed or if needed [collection](./collection-files.md) is changed.
|
||||
- 💡 `events` in base class [`StatefulVue`](./../src/presentation/components/Shared/StatefulVue.ts) makes lifecycling easier
|
||||
- 📖 See [Application state | Application layer](./presentation.md#application-state) where the state is implemented using using state pattern.
|
||||
|
||||
## Modals
|
||||
|
||||
- [Dialog.vue](./../src/presentation/components/Shared/Dialog.vue) is a shared component that can be used to show modal windows
|
||||
- Simply wrap the content inside of its slot and call `.show()` method on its reference.
|
||||
- Example:
|
||||
|
||||
```html
|
||||
<Dialog ref="testDialog">
|
||||
<div>Hello world</div>
|
||||
</Dialog>
|
||||
<div @click="$refs.testDialog.show()">Show dialog</div>
|
||||
```
|
||||
|
||||
## Sass naming convention
|
||||
|
||||
- Use lowercase for variables/functions/mixins e.g.
|
||||
- Variable: `$variable: value;`
|
||||
- Function: `@function function() {}`
|
||||
- Mixin: `@mixin mixin() {}`
|
||||
- Use - for a phrase/compound word e.g.
|
||||
- Variable: `$some-variable: value;`
|
||||
- Function: `@function some-function() {}`
|
||||
- Mixin: `@mixin some-mixin() {}`
|
||||
- Grouping and name variables from generic to specific e.g.
|
||||
- ✅ `$border-blue`, `$border-blue-light`, `$border-blue-lightest`, `$border-red`
|
||||
- ❌ `$blue-border`, `$light-blue-border`, `$lightest-blue-border`, `$red-border`
|
||||
|
||||
88
docs/templating.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# Templating
|
||||
|
||||
## Benefits of templating
|
||||
|
||||
- Generating scripts by sharing code to increase best-practice usage and maintainability.
|
||||
- Creating self-contained scripts without depending on each other that can be easily shared.
|
||||
- Use of pipes for writing cleaner code and letting pipes do dirty work.
|
||||
|
||||
## Expressions
|
||||
|
||||
- Expressions in the language are defined inside mustaches (double brackets, `{{` and `}}`).
|
||||
- Expression syntax is inspired mainly by [Go Templates](https://pkg.go.dev/text/template).
|
||||
- Expressions are used in and enabled by functions where they can be used.
|
||||
- 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).
|
||||
|
||||
### Parameter substitution
|
||||
|
||||
A simple function example:
|
||||
|
||||
```yaml
|
||||
function: EchoArgument
|
||||
parameters:
|
||||
- name: 'argument'
|
||||
code: Hello {{ $argument }} !
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
- Skips the block if the variable is absent or empty.
|
||||
- Binds its context (`.`) value of provided argument for the parameter if provided one.
|
||||
- A block is defined as `{{ with $parameterName }} Parameter value is {{ . }} here {{ end }}`.
|
||||
- The parameters used for `with` condition should be declared as optional, otherwise `with` block becomes redundant.
|
||||
- Example:
|
||||
|
||||
```yaml
|
||||
function: FunctionThatOutputsConditionally
|
||||
parameters:
|
||||
- name: 'argument'
|
||||
optional: true
|
||||
code: |-
|
||||
{{ with $argument }}
|
||||
Value is: {{ . }}
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
### Pipes
|
||||
|
||||
- Pipes are set of functions available for handling text in privacy.sexy.
|
||||
- Allows stacking actions one after another also known as "chaining".
|
||||
- Just 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.
|
||||
- Pipes are provided and defined by the compiler and consumed by collection files.
|
||||
- Pipes can be combined with [parameter substitution](#parameter-substitution) and [with](#with).
|
||||
- ❗ Pipe names must be camelCase without any space or special characters.
|
||||
- **Existing pipes**
|
||||
- `inlinePowerShell`: Converts a multi-lined PowerShell script to a single line.
|
||||
- `escapeDoubleQuotes`: Escapes `"` characters to be used inside double quotes (`"`)
|
||||
- **Example usages**
|
||||
- `{{ with $code }} echo "{{ . | inlinePowerShell }}" {{ end }}`
|
||||
- `{{ with $code }} echo "{{ . | inlinePowerShell | escapeDoubleQuotes }}" {{ end }}`
|
||||
61
docs/tests.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# Tests
|
||||
|
||||
- There are two different types of tests executed:
|
||||
1. [Unit tests](#unit-tests)
|
||||
2. [Integration tests](#integration-tests)
|
||||
3. [End-to-end (E2E) tests](#e2e-tests)
|
||||
- All tests
|
||||
- Uses [Mocha](https://mochajs.org/) and [Chai](https://www.chaijs.com/).
|
||||
- Are written in files that includes `.spec` extension.
|
||||
- 💡 You can use path/module alias `@/tests` in import statements.
|
||||
|
||||
## Unit tests
|
||||
|
||||
- Tests each component in isolation.
|
||||
- Defined in [`./tests/unit`](./../tests/unit).
|
||||
- They follow same folder structure as [`./src`](./../src).
|
||||
|
||||
### Naming
|
||||
|
||||
- Each test suite first describe the system under test.
|
||||
- E.g. tests for class `Application` is categorized under `Application`.
|
||||
- Tests for specific methods are categorized under method name (if applicable).
|
||||
- E.g. test for `run()` is categorized under `run`.
|
||||
|
||||
### Act, arrange, assert
|
||||
|
||||
- Tests use act, arrange and assert (AAA) pattern when applicable.
|
||||
- **Arrange**
|
||||
- Should set up the test case.
|
||||
- Starts with comment line `// arrange`.
|
||||
- **Act**
|
||||
- Should cover the main thing to be tested.
|
||||
- Starts with comment line `// act`.
|
||||
- **Assert**
|
||||
- Should elicit some sort of response.
|
||||
- Starts with comment line `// assert`.
|
||||
|
||||
### Stubs
|
||||
|
||||
- Stubs are defined in [`./tests/stubs`](./../tests/unit/stubs).
|
||||
- They implement dummy behavior to be functional.
|
||||
|
||||
## Integration tests
|
||||
|
||||
- Tests functionality of a component in combination with others (not isolated).
|
||||
- Ensure dependencies to third parties work as expected.
|
||||
- Defined in [`./tests/integration`](./../tests/integration).
|
||||
|
||||
## E2E tests
|
||||
|
||||
- Test the functionality and performance of a running application.
|
||||
- E2E tests are configured by vue plugin [`e2e-cypress`](https://github.com/vuejs/vue-cli/tree/dev/packages/@vue/cli-plugin-e2e-cypress#readme) for Vue CLI.
|
||||
- Names and folders are structured logically based on tests.
|
||||
- The structure is following:
|
||||
- [`cypress.json`](./../cypress.json): Cypress configuration file.
|
||||
- [`./tests/e2e/`](./../tests/e2e/): Base Cypress folder.
|
||||
- [`/specs/`](./../tests/e2e/specs/): Test files, test are named with `.spec.js` extension.
|
||||
- [`/plugins/index.js`](./../tests/e2e/plugins/index.js): Plugin file executed before project is loaded.
|
||||
- [`/support/index.js`](./../tests/e2e/support/index.js): Support file, runs before every single spec file.
|
||||
- *(Ignored)* `/videos`: Asset folder for videos taken during tests.
|
||||
- *(Ignored)* `/screenshots`: Asset folder for Screenshots taken during tests.
|
||||
1
img/architecture/app-ddd.drawio
Normal 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>
|
||||
BIN
img/architecture/app-ddd.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
1
img/architecture/gitops.drawio
Normal file
BIN
img/architecture/gitops.png
Normal file
|
After Width: | Height: | Size: 255 KiB |
BIN
img/screenshot.png
Normal file
|
After Width: | Height: | Size: 98 KiB |
50020
package-lock.json
generated
110
package.json
@@ -1,42 +1,96 @@
|
||||
{
|
||||
"name": "privacy.sexy",
|
||||
"version": "0.1.0",
|
||||
"version": "0.11.2",
|
||||
"private": true,
|
||||
"description": "Enforce privacy & security best-practices on Windows and macOS, because privacy is sexy 🍑🍆",
|
||||
"author": "undergroundwires",
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint",
|
||||
"test:unit": "vue-cli-service test:unit"
|
||||
"test:unit": "vue-cli-service test:unit",
|
||||
"test:e2e": "vue-cli-service test:e2e",
|
||||
"lint": "npm run lint:md && npm run lint:md:consistency && npm run lint:md:relative-urls && npm run lint:eslint && npm run lint:yaml",
|
||||
"electron:build": "vue-cli-service electron:build",
|
||||
"electron:serve": "vue-cli-service electron:serve",
|
||||
"lint:md": "markdownlint **/*.md --ignore node_modules",
|
||||
"lint:md:consistency": "remark . --frail --use remark-preset-lint-consistent",
|
||||
"lint:md:relative-urls": "remark . --frail --use remark-validate-links",
|
||||
"lint:eslint": "vue-cli-service lint --no-fix --mode production",
|
||||
"lint:yaml": "yamllint **/*.yaml --ignore=node_modules/**/*.yaml",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"postuninstall": "electron-builder install-app-deps",
|
||||
"test:integration": "vue-cli-service test:unit \"tests/integration/**/*.spec.ts\""
|
||||
},
|
||||
"main": "background.js",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.26",
|
||||
"@fortawesome/free-brands-svg-icons": "^5.12.0",
|
||||
"@fortawesome/free-regular-svg-icons": "^5.12.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.12.0",
|
||||
"@fortawesome/vue-fontawesome": "^0.1.9",
|
||||
"ace-builds": "^1.4.7",
|
||||
"file-saver": "^2.0.2",
|
||||
"inversify": "^5.0.1",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.36",
|
||||
"@fortawesome/free-brands-svg-icons": "^5.15.4",
|
||||
"@fortawesome/free-regular-svg-icons": "^5.15.4",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
||||
"@fortawesome/vue-fontawesome": "^2.0.6",
|
||||
"@juggle/resize-observer": "^3.3.1",
|
||||
"ace-builds": "^1.4.13",
|
||||
"core-js": "^3.18.3",
|
||||
"cross-fetch": "^3.1.4",
|
||||
"electron-progressbar": "^2.0.1",
|
||||
"file-saver": "^2.0.5",
|
||||
"install": "^0.13.0",
|
||||
"liquor-tree": "^0.2.70",
|
||||
"v-tooltip": "^2.0.2",
|
||||
"vue": "^2.6.11",
|
||||
"vue-class-component": "^7.1.0",
|
||||
"vue-property-decorator": "^8.3.0"
|
||||
"npm": "^8.1.1",
|
||||
"v-tooltip": "2.1.3",
|
||||
"vue": "^2.6.14",
|
||||
"vue-class-component": "^7.2.6",
|
||||
"vue-js-modal": "^2.0.1",
|
||||
"vue-property-decorator": "^9.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.2.7",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/ace": "0.0.42",
|
||||
"@types/file-saver": "^2.0.1",
|
||||
"@vue/cli-plugin-typescript": "^4.1.1",
|
||||
"@vue/cli-plugin-unit-mocha": "^4.1.1",
|
||||
"@vue/cli-service": "^4.1.1",
|
||||
"@vue/test-utils": "1.0.0-beta.30",
|
||||
"chai": "^4.2.0",
|
||||
"sass": "^1.24.0",
|
||||
"sass-loader": "^8.0.0",
|
||||
"@types/ace": "0.0.47",
|
||||
"@types/chai": "^4.2.22",
|
||||
"@types/file-saver": "^2.0.3",
|
||||
"@types/mocha": "^9.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||
"@typescript-eslint/parser": "^5.4.0",
|
||||
"@vue/cli-plugin-babel": "~5.0.0-rc.1",
|
||||
"@vue/cli-plugin-e2e-cypress": "~5.0.0-rc.1",
|
||||
"@vue/cli-plugin-eslint": "~5.0.0-rc.1",
|
||||
"@vue/cli-plugin-typescript": "~5.0.0-rc.1",
|
||||
"@vue/cli-plugin-unit-mocha": "~5.0.0-rc.1",
|
||||
"@vue/cli-service": "~5.0.0-rc.1",
|
||||
"@vue/eslint-config-airbnb": "^6.0.0",
|
||||
"@vue/eslint-config-typescript": "^9.1.0",
|
||||
"@vue/test-utils": "1.2.2",
|
||||
"chai": "^4.3.4",
|
||||
"cypress": "^8.3.0",
|
||||
"electron": "^15.3.0",
|
||||
"electron-devtools-installer": "^3.2.0",
|
||||
"electron-log": "^4.4.1",
|
||||
"electron-updater": "^4.3.9",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-plugin-import": "^2.25.3",
|
||||
"eslint-plugin-vue": "^8.0.3",
|
||||
"eslint-plugin-vuejs-accessibility": "^1.1.0",
|
||||
"js-yaml-loader": "^1.2.2",
|
||||
"typescript": "^3.7.4",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
"markdownlint-cli": "^0.29.0",
|
||||
"raw-loader": "^4.0.2",
|
||||
"remark-cli": "^10.0.0",
|
||||
"remark-lint-no-dead-urls": "^1.1.0",
|
||||
"remark-preset-lint-consistent": "^5.1.0",
|
||||
"remark-validate-links": "^11.0.1",
|
||||
"sass": "^1.43.3",
|
||||
"sass-loader": "10.2.0",
|
||||
"ts-loader": "9.0.1",
|
||||
"tslib": "^2.3.1",
|
||||
"typescript": "^4.4.4",
|
||||
"vue-cli-plugin-electron-builder": "^2.1.1",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"yaml-lint": "^1.2.4"
|
||||
},
|
||||
"//devDependencies": {
|
||||
"ts-loader": "Here as workaround for vue-cli-plugin-electron-builder using older webpack 4"
|
||||
},
|
||||
"homepage": "https://privacy.sexy",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/undergroundwires/privacy.sexy.git"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
autoprefixer: {}
|
||||
}
|
||||
}
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
|
||||
BIN
public/icon.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
@@ -4,7 +4,7 @@
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<title>Privacy is sexy 🍑🍆 - Enforce privacy & security on Windows</title>
|
||||
<title>Privacy is sexy 🍑🍆 - Enforce privacy & security on Windows and macOS</title>
|
||||
<meta name="robots" content="index,follow" />
|
||||
<meta name="description" content="Web tool to generate scripts for enforcing privacy & security best-practices such as stopping data collection of Windows and different softwares on it."/>
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
@@ -32,4 +32,4 @@
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
2
public/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow:
|
||||
76
src/App.vue
@@ -1,76 +0,0 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<div class="wrapper">
|
||||
<TheHeader class="row" />
|
||||
<TheSearchBar class="row" />
|
||||
<TheScripts class="row"/>
|
||||
<TheCodeArea class="row" theme="xcode" />
|
||||
<TheCodeButtons class="row" />
|
||||
<TheFooter />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Prop } from 'vue-property-decorator';
|
||||
import { ApplicationState, IApplicationState } from '@/application/State/ApplicationState';
|
||||
import TheHeader from '@/presentation/TheHeader.vue';
|
||||
import TheFooter from '@/presentation/TheFooter.vue';
|
||||
import TheCodeArea from '@/presentation/TheCodeArea.vue';
|
||||
import TheCodeButtons from '@/presentation/TheCodeButtons.vue';
|
||||
import TheSearchBar from '@/presentation/TheSearchBar.vue';
|
||||
import TheScripts from '@/presentation/Scripts/TheScripts.vue';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
TheHeader,
|
||||
TheCodeArea,
|
||||
TheCodeButtons,
|
||||
TheScripts,
|
||||
TheSearchBar,
|
||||
TheFooter,
|
||||
},
|
||||
})
|
||||
export default class App extends Vue {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "@/presentation/styles/colors.scss";
|
||||
@import "@/presentation/styles/fonts.scss";
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
background: $light-gray;
|
||||
font-family: $main-font;
|
||||
color: $slate;
|
||||
}
|
||||
|
||||
|
||||
#app {
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
max-width: 1500px;
|
||||
|
||||
.wrapper {
|
||||
margin: 0% 2% 0% 2%;
|
||||
background-color: white;
|
||||
box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.06);
|
||||
padding: 2%;
|
||||
display:flex;
|
||||
flex-direction: column;
|
||||
|
||||
.row {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@import "@/presentation/styles/tooltip.scss";
|
||||
@import "@/presentation/styles/tree.scss";
|
||||
</style>
|
||||
24
src/application/ApplicationFactory.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { IApplication } from '@/domain/IApplication';
|
||||
import { AsyncLazy } from '@/infrastructure/Threading/AsyncLazy';
|
||||
import { IApplicationFactory } from './IApplicationFactory';
|
||||
import { parseApplication } from './Parser/ApplicationParser';
|
||||
|
||||
export type ApplicationGetter = () => IApplication;
|
||||
const ApplicationGetter: ApplicationGetter = parseApplication;
|
||||
|
||||
export class ApplicationFactory implements IApplicationFactory {
|
||||
public static readonly Current: IApplicationFactory = new ApplicationFactory(ApplicationGetter);
|
||||
|
||||
private readonly getter: AsyncLazy<IApplication>;
|
||||
|
||||
protected constructor(costlyGetter: ApplicationGetter) {
|
||||
if (!costlyGetter) {
|
||||
throw new Error('undefined getter');
|
||||
}
|
||||
this.getter = new AsyncLazy<IApplication>(() => Promise.resolve(costlyGetter()));
|
||||
}
|
||||
|
||||
public getApp(): Promise<IApplication> {
|
||||
return this.getter.getValue();
|
||||
}
|
||||
}
|
||||
21
src/application/Common/Array.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
// Compares to Array<T> objects for equality, ignoring order
|
||||
export function scrambledEqual<T>(array1: readonly T[], array2: readonly T[]) {
|
||||
if (!array1) { throw new Error('undefined first array'); }
|
||||
if (!array2) { throw new Error('undefined second array'); }
|
||||
const sortedArray1 = sort(array1);
|
||||
const sortedArray2 = sort(array2);
|
||||
return sequenceEqual(sortedArray1, sortedArray2);
|
||||
function sort(array: readonly T[]) {
|
||||
return array.slice().sort();
|
||||
}
|
||||
}
|
||||
|
||||
// Compares to Array<T> objects for equality in same order
|
||||
export function sequenceEqual<T>(array1: readonly T[], array2: readonly T[]) {
|
||||
if (!array1) { throw new Error('undefined first array'); }
|
||||
if (!array2) { throw new Error('undefined second array'); }
|
||||
if (array1.length !== array2.length) {
|
||||
return false;
|
||||
}
|
||||
return array1.every((val, index) => val === array2[index]);
|
||||
}
|
||||
63
src/application/Common/Enum.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
// Because we cannot do "T extends enum" 😞 https://github.com/microsoft/TypeScript/issues/30611
|
||||
export type EnumType = number | string;
|
||||
export type EnumVariable<T extends EnumType, TEnumValue extends EnumType>
|
||||
= { [key in T]: TEnumValue };
|
||||
|
||||
export interface IEnumParser<TEnum> {
|
||||
parseEnum(value: string, propertyName: string): TEnum;
|
||||
}
|
||||
|
||||
export function createEnumParser<T extends EnumType, TEnumValue extends EnumType>(
|
||||
enumVariable: EnumVariable<T, TEnumValue>,
|
||||
): IEnumParser<TEnumValue> {
|
||||
return {
|
||||
parseEnum: (value, propertyName) => parseEnumValue(value, propertyName, enumVariable),
|
||||
};
|
||||
}
|
||||
|
||||
function parseEnumValue<T extends EnumType, TEnumValue extends EnumType>(
|
||||
value: string,
|
||||
enumName: string,
|
||||
enumVariable: EnumVariable<T, TEnumValue>,
|
||||
): TEnumValue {
|
||||
if (!value) {
|
||||
throw new Error(`undefined ${enumName}`);
|
||||
}
|
||||
if (typeof value !== 'string') {
|
||||
throw new Error(`unexpected type of ${enumName}: "${typeof value}"`);
|
||||
}
|
||||
const casedValue = getEnumNames(enumVariable)
|
||||
.find((enumValue) => enumValue.toLowerCase() === value.toLowerCase());
|
||||
if (!casedValue) {
|
||||
throw new Error(`unknown ${enumName}: "${value}"`);
|
||||
}
|
||||
return enumVariable[casedValue as keyof typeof enumVariable];
|
||||
}
|
||||
|
||||
export function getEnumNames
|
||||
<T extends EnumType, TEnumValue extends EnumType>(
|
||||
enumVariable: EnumVariable<T, TEnumValue>,
|
||||
): string[] {
|
||||
return Object
|
||||
.values(enumVariable)
|
||||
.filter((enumMember) => typeof enumMember === 'string') as string[];
|
||||
}
|
||||
|
||||
export function getEnumValues<T extends EnumType, TEnumValue extends EnumType>(
|
||||
enumVariable: EnumVariable<T, TEnumValue>,
|
||||
): TEnumValue[] {
|
||||
return getEnumNames(enumVariable)
|
||||
.map((level) => enumVariable[level]) as TEnumValue[];
|
||||
}
|
||||
|
||||
export function assertInRange<T extends EnumType, TEnumValue extends EnumType>(
|
||||
value: TEnumValue,
|
||||
enumVariable: EnumVariable<T, TEnumValue>,
|
||||
) {
|
||||
if (value === undefined) {
|
||||
throw new Error('undefined enum value');
|
||||
}
|
||||
if (!(value in enumVariable)) {
|
||||
throw new RangeError(`enum value "${value}" is out of range`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { ScriptingLanguage } from '@/domain/ScriptingLanguage';
|
||||
|
||||
export interface IScriptingLanguageFactory<T> {
|
||||
create(language: ScriptingLanguage): T;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { ScriptingLanguage } from '@/domain/ScriptingLanguage';
|
||||
import { assertInRange } from '@/application/Common/Enum';
|
||||
import { IScriptingLanguageFactory } from './IScriptingLanguageFactory';
|
||||
|
||||
type Getter<T> = () => T;
|
||||
|
||||
export abstract class ScriptingLanguageFactory<T> implements IScriptingLanguageFactory<T> {
|
||||
private readonly getters = new Map<ScriptingLanguage, Getter<T>>();
|
||||
|
||||
public create(language: ScriptingLanguage): T {
|
||||
assertInRange(language, ScriptingLanguage);
|
||||
if (!this.getters.has(language)) {
|
||||
throw new RangeError(`unknown language: "${ScriptingLanguage[language]}"`);
|
||||
}
|
||||
const getter = this.getters.get(language);
|
||||
const instance = getter();
|
||||
return instance;
|
||||
}
|
||||
|
||||
protected registerGetter(language: ScriptingLanguage, getter: Getter<T>) {
|
||||
assertInRange(language, ScriptingLanguage);
|
||||
if (!getter) {
|
||||
throw new Error('undefined getter');
|
||||
}
|
||||
if (this.getters.has(language)) {
|
||||
throw new Error(`${ScriptingLanguage[language]} is already registered`);
|
||||
}
|
||||
this.getters.set(language, getter);
|
||||
}
|
||||
}
|
||||
64
src/application/Context/ApplicationContext.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { IApplication } from '@/domain/IApplication';
|
||||
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||
import { ICategoryCollection } from '@/domain/ICategoryCollection';
|
||||
import { EventSource } from '@/infrastructure/Events/EventSource';
|
||||
import { assertInRange } from '@/application/Common/Enum';
|
||||
import { CategoryCollectionState } from './State/CategoryCollectionState';
|
||||
import { ICategoryCollectionState } from './State/ICategoryCollectionState';
|
||||
import { IApplicationContext, IApplicationContextChangedEvent } from './IApplicationContext';
|
||||
|
||||
type StateMachine = Map<OperatingSystem, ICategoryCollectionState>;
|
||||
|
||||
export class ApplicationContext implements IApplicationContext {
|
||||
public readonly contextChanged = new EventSource<IApplicationContextChangedEvent>();
|
||||
|
||||
public collection: ICategoryCollection;
|
||||
|
||||
public currentOs: OperatingSystem;
|
||||
|
||||
public get state(): ICategoryCollectionState {
|
||||
return this.states[this.collection.os];
|
||||
}
|
||||
|
||||
private readonly states: StateMachine;
|
||||
|
||||
public constructor(
|
||||
public readonly app: IApplication,
|
||||
initialContext: OperatingSystem,
|
||||
) {
|
||||
validateApp(app);
|
||||
assertInRange(initialContext, OperatingSystem);
|
||||
this.states = initializeStates(app);
|
||||
this.changeContext(initialContext);
|
||||
}
|
||||
|
||||
public changeContext(os: OperatingSystem): void {
|
||||
if (this.currentOs === os) {
|
||||
return;
|
||||
}
|
||||
this.collection = this.app.getCollection(os);
|
||||
if (!this.collection) {
|
||||
throw new Error(`os "${OperatingSystem[os]}" is not defined in application`);
|
||||
}
|
||||
const event: IApplicationContextChangedEvent = {
|
||||
newState: this.states[os],
|
||||
oldState: this.states[this.currentOs],
|
||||
};
|
||||
this.contextChanged.notify(event);
|
||||
this.currentOs = os;
|
||||
}
|
||||
}
|
||||
|
||||
function validateApp(app: IApplication) {
|
||||
if (!app) {
|
||||
throw new Error('undefined app');
|
||||
}
|
||||
}
|
||||
|
||||
function initializeStates(app: IApplication): StateMachine {
|
||||
const machine = new Map<OperatingSystem, ICategoryCollectionState>();
|
||||
for (const collection of app.collections) {
|
||||
machine[collection.os] = new CategoryCollectionState(collection);
|
||||
}
|
||||
return machine;
|
||||
}
|
||||
32
src/application/Context/ApplicationContextFactory.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { IApplicationContext } from '@/application/Context/IApplicationContext';
|
||||
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||
import { IApplication } from '@/domain/IApplication';
|
||||
import { Environment } from '../Environment/Environment';
|
||||
import { IEnvironment } from '../Environment/IEnvironment';
|
||||
import { IApplicationFactory } from '../IApplicationFactory';
|
||||
import { ApplicationFactory } from '../ApplicationFactory';
|
||||
import { ApplicationContext } from './ApplicationContext';
|
||||
|
||||
export async function buildContext(
|
||||
factory: IApplicationFactory = ApplicationFactory.Current,
|
||||
environment = Environment.CurrentEnvironment,
|
||||
): Promise<IApplicationContext> {
|
||||
if (!factory) { throw new Error('undefined factory'); }
|
||||
if (!environment) { throw new Error('undefined environment'); }
|
||||
const app = await factory.getApp();
|
||||
const os = getInitialOs(app, environment);
|
||||
return new ApplicationContext(app, os);
|
||||
}
|
||||
|
||||
function getInitialOs(app: IApplication, environment: IEnvironment): OperatingSystem {
|
||||
const currentOs = environment.os;
|
||||
const supportedOsList = app.getSupportedOsList();
|
||||
if (supportedOsList.includes(currentOs)) {
|
||||
return currentOs;
|
||||
}
|
||||
supportedOsList.sort((os1, os2) => {
|
||||
const getPriority = (os: OperatingSystem) => app.getCollection(os).totalScripts;
|
||||
return getPriority(os2) - getPriority(os1);
|
||||
});
|
||||
return supportedOsList[0];
|
||||
}
|
||||
20
src/application/Context/IApplicationContext.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||
import { IEventSource } from '@/infrastructure/Events/IEventSource';
|
||||
import { IApplication } from '@/domain/IApplication';
|
||||
import { ICategoryCollectionState, IReadOnlyCategoryCollectionState } from './State/ICategoryCollectionState';
|
||||
|
||||
export interface IReadOnlyApplicationContext {
|
||||
readonly app: IApplication;
|
||||
readonly state: IReadOnlyCategoryCollectionState;
|
||||
readonly contextChanged: IEventSource<IApplicationContextChangedEvent>;
|
||||
}
|
||||
|
||||
export interface IApplicationContext extends IReadOnlyApplicationContext {
|
||||
readonly state: ICategoryCollectionState;
|
||||
changeContext(os: OperatingSystem): void;
|
||||
}
|
||||
|
||||
export interface IApplicationContextChangedEvent {
|
||||
readonly newState: ICategoryCollectionState;
|
||||
readonly oldState: ICategoryCollectionState;
|
||||
}
|
||||
26
src/application/Context/State/CategoryCollectionState.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { ICategoryCollection } from '@/domain/ICategoryCollection';
|
||||
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||
import { UserFilter } from './Filter/UserFilter';
|
||||
import { IUserFilter } from './Filter/IUserFilter';
|
||||
import { ApplicationCode } from './Code/ApplicationCode';
|
||||
import { UserSelection } from './Selection/UserSelection';
|
||||
import { IUserSelection } from './Selection/IUserSelection';
|
||||
import { ICategoryCollectionState } from './ICategoryCollectionState';
|
||||
import { IApplicationCode } from './Code/IApplicationCode';
|
||||
|
||||
export class CategoryCollectionState implements ICategoryCollectionState {
|
||||
public readonly os: OperatingSystem;
|
||||
|
||||
public readonly code: IApplicationCode;
|
||||
|
||||
public readonly selection: IUserSelection;
|
||||
|
||||
public readonly filter: IUserFilter;
|
||||
|
||||
public constructor(readonly collection: ICategoryCollection) {
|
||||
this.selection = new UserSelection(collection, []);
|
||||
this.code = new ApplicationCode(this.selection, collection.scripting);
|
||||
this.filter = new UserFilter(collection);
|
||||
this.os = collection.os;
|
||||
}
|
||||
}
|
||||
41
src/application/Context/State/Code/ApplicationCode.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { SelectedScript } from '@/application/Context/State/Selection/SelectedScript';
|
||||
import { IReadOnlyUserSelection } from '@/application/Context/State/Selection/IUserSelection';
|
||||
import { EventSource } from '@/infrastructure/Events/EventSource';
|
||||
import { IScriptingDefinition } from '@/domain/IScriptingDefinition';
|
||||
import { CodeChangedEvent } from './Event/CodeChangedEvent';
|
||||
import { CodePosition } from './Position/CodePosition';
|
||||
import { ICodeChangedEvent } from './Event/ICodeChangedEvent';
|
||||
import { UserScriptGenerator } from './Generation/UserScriptGenerator';
|
||||
import { IApplicationCode } from './IApplicationCode';
|
||||
import { IUserScriptGenerator } from './Generation/IUserScriptGenerator';
|
||||
|
||||
export class ApplicationCode implements IApplicationCode {
|
||||
public readonly changed = new EventSource<ICodeChangedEvent>();
|
||||
|
||||
public current: string;
|
||||
|
||||
private scriptPositions = new Map<SelectedScript, CodePosition>();
|
||||
|
||||
constructor(
|
||||
userSelection: IReadOnlyUserSelection,
|
||||
private readonly scriptingDefinition: IScriptingDefinition,
|
||||
private readonly generator: IUserScriptGenerator = new UserScriptGenerator(),
|
||||
) {
|
||||
if (!userSelection) { throw new Error('userSelection is null or undefined'); }
|
||||
if (!scriptingDefinition) { throw new Error('scriptingDefinition is null or undefined'); }
|
||||
if (!generator) { throw new Error('generator is null or undefined'); }
|
||||
this.setCode(userSelection.selectedScripts);
|
||||
userSelection.changed.on((scripts) => {
|
||||
this.setCode(scripts);
|
||||
});
|
||||
}
|
||||
|
||||
private setCode(scripts: ReadonlyArray<SelectedScript>): void {
|
||||
const oldScripts = Array.from(this.scriptPositions.keys());
|
||||
const code = this.generator.buildCode(scripts, this.scriptingDefinition);
|
||||
this.current = code.code;
|
||||
this.scriptPositions = code.scriptPositions;
|
||||
const event = new CodeChangedEvent(code.code, oldScripts, code.scriptPositions);
|
||||
this.changed.notify(event);
|
||||
}
|
||||
}
|
||||
71
src/application/Context/State/Code/Event/CodeChangedEvent.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { IScript } from '@/domain/IScript';
|
||||
import { ICodePosition } from '@/application/Context/State/Code/Position/ICodePosition';
|
||||
import { SelectedScript } from '../../Selection/SelectedScript';
|
||||
import { ICodeChangedEvent } from './ICodeChangedEvent';
|
||||
|
||||
export class CodeChangedEvent implements ICodeChangedEvent {
|
||||
public readonly code: string;
|
||||
|
||||
public readonly addedScripts: ReadonlyArray<IScript>;
|
||||
|
||||
public readonly removedScripts: ReadonlyArray<IScript>;
|
||||
|
||||
public readonly changedScripts: ReadonlyArray<IScript>;
|
||||
|
||||
private readonly scripts: Map<IScript, ICodePosition>;
|
||||
|
||||
constructor(
|
||||
code: string,
|
||||
oldScripts: ReadonlyArray<SelectedScript>,
|
||||
scripts: Map<SelectedScript, ICodePosition>,
|
||||
) {
|
||||
ensureAllPositionsExist(code, Array.from(scripts.values()));
|
||||
this.code = code;
|
||||
const newScripts = Array.from(scripts.keys());
|
||||
this.addedScripts = selectIfNotExists(newScripts, oldScripts);
|
||||
this.removedScripts = selectIfNotExists(oldScripts, newScripts);
|
||||
this.changedScripts = getChangedScripts(oldScripts, newScripts);
|
||||
this.scripts = new Map<IScript, ICodePosition>();
|
||||
scripts.forEach((position, selection) => {
|
||||
this.scripts.set(selection.script, position);
|
||||
});
|
||||
}
|
||||
|
||||
public isEmpty(): boolean {
|
||||
return this.scripts.size === 0;
|
||||
}
|
||||
|
||||
public getScriptPositionInCode(script: IScript): ICodePosition {
|
||||
return this.scripts.get(script);
|
||||
}
|
||||
}
|
||||
|
||||
function ensureAllPositionsExist(script: string, positions: ReadonlyArray<ICodePosition>) {
|
||||
const totalLines = script.split(/\r\n|\r|\n/).length;
|
||||
const missingPositions = positions.filter((position) => position.endLine > totalLines);
|
||||
if (missingPositions.length > 0) {
|
||||
throw new Error(
|
||||
`Out of range script end line: "${missingPositions.map((pos) => pos.endLine).join('", "')}"`
|
||||
+ `(total code lines: ${totalLines}).`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function getChangedScripts(
|
||||
oldScripts: ReadonlyArray<SelectedScript>,
|
||||
newScripts: ReadonlyArray<SelectedScript>,
|
||||
): ReadonlyArray<IScript> {
|
||||
return newScripts
|
||||
.filter((newScript) => oldScripts.find((oldScript) => oldScript.id === newScript.id
|
||||
&& oldScript.revert !== newScript.revert))
|
||||
.map((selection) => selection.script);
|
||||
}
|
||||
|
||||
function selectIfNotExists(
|
||||
selectableContainer: ReadonlyArray<SelectedScript>,
|
||||
test: ReadonlyArray<SelectedScript>,
|
||||
) {
|
||||
return selectableContainer
|
||||
.filter((script) => !test.find((oldScript) => oldScript.id === script.id))
|
||||
.map((selection) => selection.script);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { IScript } from '@/domain/IScript';
|
||||
import { ICodePosition } from '@/application/Context/State/Code/Position/ICodePosition';
|
||||
|
||||
export interface ICodeChangedEvent {
|
||||
readonly code: string;
|
||||
addedScripts: ReadonlyArray<IScript>;
|
||||
removedScripts: ReadonlyArray<IScript>;
|
||||
changedScripts: ReadonlyArray<IScript>;
|
||||
isEmpty(): boolean;
|
||||
getScriptPositionInCode(script: IScript): ICodePosition;
|
||||
}
|
||||
68
src/application/Context/State/Code/Generation/CodeBuilder.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { ICodeBuilder } from './ICodeBuilder';
|
||||
|
||||
const NewLine = '\n';
|
||||
const TotalFunctionSeparatorChars = 58;
|
||||
|
||||
export abstract class CodeBuilder implements ICodeBuilder {
|
||||
private readonly lines = new Array<string>();
|
||||
|
||||
// Returns current line starting from 0 (no lines), or 1 (have single line)
|
||||
public get currentLine(): number {
|
||||
return this.lines.length;
|
||||
}
|
||||
|
||||
public appendLine(code?: string): CodeBuilder {
|
||||
if (!code) {
|
||||
this.lines.push('');
|
||||
return this;
|
||||
}
|
||||
const lines = code.match(/[^\r\n]+/g);
|
||||
this.lines.push(...lines);
|
||||
return this;
|
||||
}
|
||||
|
||||
public appendTrailingHyphensCommentLine(
|
||||
totalRepeatHyphens: number = TotalFunctionSeparatorChars,
|
||||
): CodeBuilder {
|
||||
return this.appendCommentLine('-'.repeat(totalRepeatHyphens));
|
||||
}
|
||||
|
||||
public appendCommentLine(commentLine?: string): CodeBuilder {
|
||||
this.lines.push(`${this.getCommentDelimiter()} ${commentLine}`);
|
||||
return this;
|
||||
}
|
||||
|
||||
public appendFunction(name: string, code: string): CodeBuilder {
|
||||
if (!name) { throw new Error('name cannot be empty or null'); }
|
||||
if (!code) { throw new Error('code cannot be empty or null'); }
|
||||
return this
|
||||
.appendCommentLineWithHyphensAround(name)
|
||||
.appendLine(this.writeStandardOut(`--- ${name}`))
|
||||
.appendLine(code)
|
||||
.appendTrailingHyphensCommentLine();
|
||||
}
|
||||
|
||||
public appendCommentLineWithHyphensAround(
|
||||
sectionName: string,
|
||||
totalRepeatHyphens: number = TotalFunctionSeparatorChars,
|
||||
): CodeBuilder {
|
||||
if (!sectionName) { throw new Error('sectionName cannot be empty or null'); }
|
||||
if (sectionName.length >= totalRepeatHyphens) {
|
||||
return this.appendCommentLine(sectionName);
|
||||
}
|
||||
const firstHyphens = '-'.repeat(Math.floor((totalRepeatHyphens - sectionName.length) / 2));
|
||||
const secondHyphens = '-'.repeat(Math.ceil((totalRepeatHyphens - sectionName.length) / 2));
|
||||
return this
|
||||
.appendTrailingHyphensCommentLine()
|
||||
.appendCommentLine(firstHyphens + sectionName + secondHyphens)
|
||||
.appendTrailingHyphensCommentLine(TotalFunctionSeparatorChars);
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
return this.lines.join(NewLine);
|
||||
}
|
||||
|
||||
protected abstract getCommentDelimiter(): string;
|
||||
|
||||
protected abstract writeStandardOut(text: string): string;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { ScriptingLanguageFactory } from '@/application/Common/ScriptingLanguage/ScriptingLanguageFactory';
|
||||
import { ScriptingLanguage } from '@/domain/ScriptingLanguage';
|
||||
import { ICodeBuilder } from './ICodeBuilder';
|
||||
import { BatchBuilder } from './Languages/BatchBuilder';
|
||||
import { ShellBuilder } from './Languages/ShellBuilder';
|
||||
import { ICodeBuilderFactory } from './ICodeBuilderFactory';
|
||||
|
||||
export class CodeBuilderFactory
|
||||
extends ScriptingLanguageFactory<ICodeBuilder>
|
||||
implements ICodeBuilderFactory {
|
||||
constructor() {
|
||||
super();
|
||||
this.registerGetter(ScriptingLanguage.shellscript, () => new ShellBuilder());
|
||||
this.registerGetter(ScriptingLanguage.batchfile, () => new BatchBuilder());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export interface ICodeBuilder {
|
||||
currentLine: number;
|
||||
appendLine(code?: string): ICodeBuilder;
|
||||
appendTrailingHyphensCommentLine(totalRepeatHyphens: number): ICodeBuilder;
|
||||
appendCommentLine(commentLine?: string): ICodeBuilder;
|
||||
appendCommentLineWithHyphensAround(sectionName: string, totalRepeatHyphens: number): ICodeBuilder;
|
||||
appendFunction(name: string, code: string): ICodeBuilder;
|
||||
toString(): string;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import { IScriptingLanguageFactory } from '@/application/Common/ScriptingLanguage/IScriptingLanguageFactory';
|
||||
import { ICodeBuilder } from './ICodeBuilder';
|
||||
|
||||
export type ICodeBuilderFactory = IScriptingLanguageFactory<ICodeBuilder>;
|
||||
@@ -0,0 +1,7 @@
|
||||
import { SelectedScript } from '@/application/Context/State/Selection/SelectedScript';
|
||||
import { ICodePosition } from '@/application/Context/State/Code/Position/ICodePosition';
|
||||
|
||||
export interface IUserScript {
|
||||
code: string;
|
||||
scriptPositions: Map<SelectedScript, ICodePosition>;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { SelectedScript } from '@/application/Context/State/Selection/SelectedScript';
|
||||
import { IScriptingDefinition } from '@/domain/IScriptingDefinition';
|
||||
import { IUserScript } from './IUserScript';
|
||||
|
||||
export interface IUserScriptGenerator {
|
||||
buildCode(
|
||||
selectedScripts: ReadonlyArray<SelectedScript>,
|
||||
scriptingDefinition: IScriptingDefinition): IUserScript;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { CodeBuilder } from '@/application/Context/State/Code/Generation/CodeBuilder';
|
||||
|
||||
export class BatchBuilder extends CodeBuilder {
|
||||
protected getCommentDelimiter(): string {
|
||||
return '::';
|
||||
}
|
||||
|
||||
protected writeStandardOut(text: string): string {
|
||||
return `echo ${escapeForEcho(text)}`;
|
||||
}
|
||||
}
|
||||
|
||||
function escapeForEcho(text: string) {
|
||||
return text
|
||||
.replace(/&/g, '^&')
|
||||
.replace(/%/g, '%%');
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { CodeBuilder } from '@/application/Context/State/Code/Generation/CodeBuilder';
|
||||
|
||||
export class ShellBuilder extends CodeBuilder {
|
||||
protected getCommentDelimiter(): string {
|
||||
return '#';
|
||||
}
|
||||
|
||||
protected writeStandardOut(text: string): string {
|
||||
return `echo '${escapeForEcho(text)}'`;
|
||||
}
|
||||
}
|
||||
|
||||
function escapeForEcho(text: string) {
|
||||
return text
|
||||
.replace(/'/g, '\'\\\'\'');
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import { SelectedScript } from '@/application/Context/State/Selection/SelectedScript';
|
||||
import { ICodePosition } from '@/application/Context/State/Code/Position/ICodePosition';
|
||||
import { IScriptingDefinition } from '@/domain/IScriptingDefinition';
|
||||
import { CodePosition } from '../Position/CodePosition';
|
||||
import { IUserScriptGenerator } from './IUserScriptGenerator';
|
||||
import { IUserScript } from './IUserScript';
|
||||
import { ICodeBuilder } from './ICodeBuilder';
|
||||
import { ICodeBuilderFactory } from './ICodeBuilderFactory';
|
||||
import { CodeBuilderFactory } from './CodeBuilderFactory';
|
||||
|
||||
export class UserScriptGenerator implements IUserScriptGenerator {
|
||||
constructor(private readonly codeBuilderFactory: ICodeBuilderFactory = new CodeBuilderFactory()) {
|
||||
|
||||
}
|
||||
|
||||
public buildCode(
|
||||
selectedScripts: ReadonlyArray<SelectedScript>,
|
||||
scriptingDefinition: IScriptingDefinition,
|
||||
): IUserScript {
|
||||
if (!selectedScripts) { throw new Error('undefined scripts'); }
|
||||
if (!scriptingDefinition) { throw new Error('undefined definition'); }
|
||||
if (!selectedScripts.length) {
|
||||
return { code: '', scriptPositions: new Map<SelectedScript, ICodePosition>() };
|
||||
}
|
||||
let builder = this.codeBuilderFactory.create(scriptingDefinition.language);
|
||||
builder = initializeCode(scriptingDefinition.startCode, builder);
|
||||
const scriptPositions = selectedScripts.reduce((result, selection) => {
|
||||
return appendSelection(selection, result, builder);
|
||||
}, new Map<SelectedScript, ICodePosition>());
|
||||
const code = finalizeCode(builder, scriptingDefinition.endCode);
|
||||
return { code, scriptPositions };
|
||||
}
|
||||
}
|
||||
|
||||
function initializeCode(startCode: string, builder: ICodeBuilder): ICodeBuilder {
|
||||
if (!startCode) {
|
||||
return builder;
|
||||
}
|
||||
return builder
|
||||
.appendLine(startCode)
|
||||
.appendLine();
|
||||
}
|
||||
|
||||
function finalizeCode(builder: ICodeBuilder, endCode: string): string {
|
||||
if (!endCode) {
|
||||
return builder.toString();
|
||||
}
|
||||
return builder.appendLine()
|
||||
.appendLine(endCode)
|
||||
.toString();
|
||||
}
|
||||
|
||||
function appendSelection(
|
||||
selection: SelectedScript,
|
||||
scriptPositions: Map<SelectedScript, ICodePosition>,
|
||||
builder: ICodeBuilder,
|
||||
): Map<SelectedScript, ICodePosition> {
|
||||
// Start from next line because first line will be empty to separate scripts
|
||||
const startPosition = builder.currentLine + 1;
|
||||
appendCode(selection, builder);
|
||||
const endPosition = builder.currentLine - 1;
|
||||
builder.appendLine();
|
||||
const position = new CodePosition(startPosition, endPosition);
|
||||
scriptPositions.set(selection, position);
|
||||
return scriptPositions;
|
||||
}
|
||||
|
||||
function appendCode(selection: SelectedScript, builder: ICodeBuilder): ICodeBuilder {
|
||||
const { script } = selection;
|
||||
const name = selection.revert ? `${script.name} (revert)` : script.name;
|
||||
const scriptCode = selection.revert ? script.code.revert : script.code.execute;
|
||||
return builder
|
||||
.appendLine()
|
||||
.appendFunction(name, scriptCode);
|
||||
}
|
||||
7
src/application/Context/State/Code/IApplicationCode.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { IEventSource } from '@/infrastructure/Events/IEventSource';
|
||||
import { ICodeChangedEvent } from './Event/ICodeChangedEvent';
|
||||
|
||||
export interface IApplicationCode {
|
||||
readonly changed: IEventSource<ICodeChangedEvent>;
|
||||
readonly current: string;
|
||||
}
|
||||
25
src/application/Context/State/Code/Position/CodePosition.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { ICodePosition } from './ICodePosition';
|
||||
|
||||
export class CodePosition implements ICodePosition {
|
||||
public get totalLines(): number {
|
||||
return this.endLine - this.startLine;
|
||||
}
|
||||
|
||||
constructor(
|
||||
public readonly startLine: number,
|
||||
public readonly endLine: number,
|
||||
) {
|
||||
if (startLine < 0) {
|
||||
throw new Error('Code cannot start in a negative line');
|
||||
}
|
||||
if (endLine < 0) {
|
||||
throw new Error('Code cannot end in a negative line');
|
||||
}
|
||||
if (endLine === startLine) {
|
||||
throw new Error('Empty code');
|
||||
}
|
||||
if (endLine < startLine) {
|
||||
throw new Error('End line cannot be less than start line');
|
||||
}
|
||||
}
|
||||
}
|
||||