Created
May 18, 2025 18:37
-
-
Save felschr/dfab36dc1af1f71b3ad9a019fab4100e to your computer and use it in GitHub Desktop.
Parsing & editing Cookies & Site Data Exceptions (`permissions.sqlite`) via nushell script.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #! /usr/bin/env nu | |
| print "This script synchronizes site data & cookie exceptions for Firefox-based browsers with a TOML config file." | |
| let browsers = [ | |
| { name: "Firefox" path: "~/.mozilla/firefox" } | |
| { name: "Tor Browser" path: "~/.tor project/firefox" } | |
| { name: "Mullvad Browser" path: "~/.mullvad/mullvadbrowser" } | |
| ] | |
| let browser = $browsers | input list --display name --fuzzy "Select your browser" | |
| print $"Looking for profiles in ($browser.path)" | |
| let profiles = ls --short-names ...(glob $browser.path) | where type == "dir" | get name | |
| let profile = $profiles | input list --fuzzy "Select the profile you want to change" | |
| let db_file = $"($browser.path)/($profile)/permissions.sqlite" | |
| let config_types = [ | |
| [id name default_path]; | |
| ["toml" "TOML" "secrets/firefox/site-data-exceptions.toml"] | |
| ["toml-age" "TOML (age-encrypted)" "firefox/site-data-exceptions.toml.age"] | |
| ] | |
| let config_type = $config_types | input list --display name --fuzzy "Select your config type" | |
| let agenix_path = match $config_type.id { | |
| "toml" => { }, | |
| "toml-age" => { input --default "secrets" "Select your agenix path (location of `secrets.nix`)" }, | |
| } | |
| let config_file = input --default $config_type.default_path "Select your config file" | |
| let config_file = match $config_type.id { | |
| "toml" => { $config_file }, | |
| "toml-age" => { $config_file | str replace -r $"^($agenix_path)/" '' }, | |
| } | |
| let config = match $config_type.id { | |
| "toml" => { $config_file | open }, | |
| "toml-age" => { (cd $agenix_path; agenix -d $config_file) | from toml }, | |
| } | |
| # get origin & origin attributes separately from single origin string | |
| def split_origin []: string -> record { | |
| let x = $in | split column '^' origin attrs | into record | |
| let attrs = if $x.attrs? != null { | |
| $x.attrs | split row '&' | each {|attr| $attr | split row '='} | into record | |
| } else { {} } | |
| { origin: $in origin_short: $x.origin } | merge $attrs | |
| } | |
| let db = $db_file | open | |
| let exceptions_db = $db | get moz_perms | |
| | where type == "cookie" and permission == 1 and expireType == 0 and expireTime == 0 | |
| | each {|x| $x | merge ($x.origin | split_origin) } | |
| let exceptions_config = $config | get $profile | each {|origin| $origin | split_origin } | |
| let exceptions_to_insert = $exceptions_config | |
| | filter {|x| ($exceptions_db | where origin_short == $x.origin_short | length) == 0 } | |
| | each {|x| { origin: $x.origin } } | |
| let exceptions_to_update = $exceptions_config | |
| | each {|x| | |
| let results = $exceptions_db | where origin_short == $x.origin_short and origin != $x.origin | |
| let result = $results.0? | |
| if $result != null { | |
| { id: $result.id origin: $x.origin origin_old: $result.origin } | |
| } else { null } | |
| } | |
| let exceptions_to_delete = $exceptions_db | |
| | filter {|x| ($exceptions_config | where origin_short == $x.origin_short | length) == 0 } | |
| | each {|x| { id: $x.id origin: $x.origin } } | |
| let needs_insert = ($exceptions_to_insert | length) > 0 | |
| let needs_update = ($exceptions_to_update | length) > 0 | |
| let needs_delete = ($exceptions_to_delete | length) > 0 | |
| let needs_changes = $needs_insert or $needs_update or $needs_delete | |
| if $needs_changes == false { | |
| print "No changes neccessary" | |
| exit | |
| } | |
| mut available_actions = [] | |
| if $needs_insert { | |
| print "Exceptions to insert:" | |
| print $exceptions_to_insert | |
| $available_actions = $available_actions | append "insert" | |
| } | |
| if $needs_update { | |
| print "Exceptions to update:" | |
| print $exceptions_to_update | |
| $available_actions = $available_actions | append "update" | |
| } | |
| if $needs_delete { | |
| print "Exceptions to delete:" | |
| print $exceptions_to_delete | |
| $available_actions = $available_actions | append "delete" | |
| } | |
| let prompt = "Which of the changes above should be applied?" | |
| let actions = $available_actions | input list --multi $prompt | |
| if ($actions | length) > 0 { | |
| let time = (date now | into int) / 1000000 | into int | |
| if $needs_insert and "insert" in $actions { | |
| $exceptions_to_insert | each {|x| | |
| $db | query db ' | |
| INSERT INTO moz_perms (origin, type, permission, expireType, expireTime, modificationTime) | |
| VALUES (:origin, "cookie", 1, 0, 0, :time) | |
| ' --params { origin: $x.origin time: $time } | |
| } | |
| print "Successfully inserted new records" | |
| } | |
| if $needs_update and "update" in $actions { | |
| $exceptions_to_update | each {|x| | |
| $db | query db ' | |
| UPDATE moz_perms | |
| SET origin = :origin, modificationTime = :time | |
| WHERE id = :id | |
| ' --params { id: $x.id origin: $x.origin time: $time } | |
| } | |
| print "Successfully updated changed records" | |
| } | |
| if $needs_delete and "delete" in $actions { | |
| $exceptions_to_delete | each {|x| | |
| $db | query db 'DELETE FROM moz_perms WHERE id = :id' --params { id: $x.id } | |
| } | |
| print "Successfully deleted missing records" | |
| } | |
| } else { | |
| print "Not applying any changes" | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Latest version should usually be available in my NixOS Config:
https://git.felschr.com/felschr/nixos-config/src/branch/main/scripts/firefox-sync-exceptions.nu