Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/stores/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ interface State {
showYearly: boolean;
useMultidevice: boolean;
requestTimeout: number;
// Server configuration
cors: string;
cors_regex: string;
cors_allow_aw_chrome_extension: boolean;
cors_allow_all_mozilla_extension: boolean;

// Set to true if settings loaded
_loaded: boolean;
Expand Down Expand Up @@ -83,6 +88,10 @@ export const useSettingsStore = defineStore('settings', {
showYearly: false,
useMultidevice: false,
requestTimeout: 30,
cors: '',
cors_regex: '',
cors_allow_aw_chrome_extension: true,
cors_allow_all_mozilla_extension: false,

_loaded: false,
}),
Expand Down
78 changes: 78 additions & 0 deletions src/views/settings/ServerSettings.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<template lang="pug">
div
h4.mb-3 Security & CORS

b-alert(show variant="info" class="mb-4")
h5.alert-heading Require Restart
p.mb-0 Changing settings in this section requires stopping and restarting the server for the changes to take effect.

b-form-group(label="Fixed CORS origins" label-cols-md=4 description="Configure general CORS origins with exact matches (e.g. http://localhost:8080). Comma-separated.")
b-input(v-model="cors" type="text")

b-form-group(label="Regex CORS origins" label-cols-md=4 description="Configure CORS origins with regular expressions. Useful for browser extensions (e.g. chrome-extension://.* or moz-extension://.*). Comma-separated.")
b-input(v-model="corsregex" type="text")

h5.mt-4 Extensions Shortcuts
b-form-group(label-cols-md=4)
b-form-checkbox(v-model="cors_allow_aw_chrome_extension") Allow ActivityWatch extension (Chrome)
template(#description)
div Chrome extensions use a stable, persistent ID, so the official extension is reliably supported.

b-form-group(label-cols-md=4)
b-form-checkbox(v-model="cors_allow_all_mozilla_extension") Allow all Firefox extensions (DANGEROUS)
template(#description)
div Every version of a Mozilla extension has its own ID to avoid fingerprinting. This is why you must either allow all extensions or manually configure your specific ID.
div.mt-2.text-danger(v-if="cors_allow_all_mozilla_extension")
| ⚠️ DANGEROUS: Not recommended for security. If enabled, any installed extension can access your ActivityWatch data. Use this only if you know what extensions you have and assume full responsibility.
div(v-else)
| Recommended for security. To allow a specific extension safely:
ol.mt-2.mb-1
li Go to <code>about:debugging#/runtime/this-firefox</code> in your browser.
li Look for your extension and copy the <b>Manifest URL</b> (e.g. <code>moz-extension://4b931c07dededdedff152/manifest.json</code>).
li Remove <code>manifest.json</code> from the end (to get <code>moz-extension://4b931c07dededdedff152</code>).
li Paste it into the <b>Regex CORS origins</b> field above (use a comma to separate if not empty).
Comment on lines +29 to +33
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Regex field instructions advise pasting literal URLs containing unescaped dots

Step 3 tells the user to paste a raw moz-extension://... URL (e.g. moz-extension://4b931c07deded...ff152) into the Regex CORS origins field. However, the dots (.) in that URL are regex metacharacters that match any character, so the pattern will also match origins with different characters in those positions. This could allow an unintended extension to bypass the CORS check.

Consider updating the instructions to advise users to escape literal dots with \., or direct them to paste the origin into the Fixed CORS origins field instead (which uses exact matching), if the backend supports it.



</template>

<script lang="ts">
import { useSettingsStore } from '~/stores/settings';

export default {

computed: {
cors: {
get() {
return useSettingsStore().cors;
},
set(cors) {
useSettingsStore().update({ cors });
},
},
corsregex: {
get() {
return useSettingsStore().cors_regex;
},
set(cors_regex) {
useSettingsStore().update({ cors_regex });
},
},
cors_allow_aw_chrome_extension: {
get() {
return useSettingsStore().cors_allow_aw_chrome_extension;
},
set(cors_allow_aw_chrome_extension) {
useSettingsStore().update({ cors_allow_aw_chrome_extension });
},
},
cors_allow_all_mozilla_extension: {
get() {
return useSettingsStore().cors_allow_all_mozilla_extension;
},
set(cors_allow_all_mozilla_extension) {
useSettingsStore().update({ cors_allow_all_mozilla_extension });
},
},
},
};
</script>
6 changes: 6 additions & 0 deletions src/views/settings/Settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ div
hr

DeveloperSettings

hr

ServerSettings
</template>

<script lang="ts">
Expand All @@ -49,6 +53,7 @@ import ReleaseNotificationSettings from '~/views/settings/ReleaseNotificationSet
import CategorizationSettings from '~/views/settings/CategorizationSettings.vue';
import LandingPageSettings from '~/views/settings/LandingPageSettings.vue';
import DeveloperSettings from '~/views/settings/DeveloperSettings.vue';
import ServerSettings from '~/views/settings/ServerSettings.vue';
import Theme from '~/views/settings/Theme.vue';
import ColorSettings from '~/views/settings/ColorSettings.vue';
import ActivePatternSettings from '~/views/settings/ActivePatternSettings.vue';
Expand All @@ -64,6 +69,7 @@ export default {
Theme,
ColorSettings,
DeveloperSettings,
ServerSettings,
ActivePatternSettings,
},
beforeRouteLeave(to, from, next) {
Expand Down