diff options
author | Soispha <soispha@vhack.eu> | 2023-04-28 16:12:08 +0200 |
---|---|---|
committer | Soispha <soispha@vhack.eu> | 2023-05-09 19:32:52 +0200 |
commit | 558cde37c66b29807c8cb536f0a2236a8acad49e (patch) | |
tree | c35aa94d28db51a55e81c1ff17b0718267cb5137 /home-manager | |
parent | Fix(hm/conf/keepassxc): Rework config file (diff) | |
download | nixos-config-558cde37c66b29807c8cb536f0a2236a8acad49e.tar.gz nixos-config-558cde37c66b29807c8cb536f0a2236a8acad49e.zip |
Refactor(hm/conf/firefox): For a cleaner default.nix
Diffstat (limited to '')
-rw-r--r-- | home-manager/config/firefox/config/bookmarks/default.nix | 16 | ||||
-rw-r--r-- | home-manager/config/firefox/config/chrome/userChrome.css (renamed from home-manager/config/firefox/chrome/userChrome.css) | 0 | ||||
-rw-r--r-- | home-manager/config/firefox/config/extensions/extensions.json (renamed from home-manager/config/firefox/settings/extensions.json) | 0 | ||||
-rw-r--r-- | home-manager/config/firefox/config/prefs/default.nix | 73 | ||||
-rw-r--r-- | home-manager/config/firefox/config/prefs/override.js (renamed from home-manager/config/firefox/settings/override.js) | 0 | ||||
-rw-r--r-- | home-manager/config/firefox/config/search/engines/default.nix | 59 | ||||
-rw-r--r-- | home-manager/config/firefox/default.nix | 244 | ||||
-rw-r--r-- | home-manager/config/firefox/functions/bookmarks/default.nix | 49 | ||||
-rw-r--r-- | home-manager/config/firefox/functions/extensions/default.nix | 26 | ||||
-rw-r--r-- | home-manager/config/firefox/functions/extensions/video-pauser.nix | 31 | ||||
-rwxr-xr-x | home-manager/config/firefox/scripts/update_extensions | 2 |
11 files changed, 262 insertions, 238 deletions
diff --git a/home-manager/config/firefox/config/bookmarks/default.nix b/home-manager/config/firefox/config/bookmarks/default.nix new file mode 100644 index 00000000..51f5d432 --- /dev/null +++ b/home-manager/config/firefox/config/bookmarks/default.nix @@ -0,0 +1,16 @@ +[ + { + name = "Feed - Piped"; + url = "https://piped.video/feed"; + } + + { + name = "DeepL Translate"; + url = "https://www.deepl.com/translator#en/de/test"; + } + + { + name = "HM Options"; + url = "https://mipmip.github.io/home-manager-option-search/"; + } +] diff --git a/home-manager/config/firefox/chrome/userChrome.css b/home-manager/config/firefox/config/chrome/userChrome.css index 0b3aff77..0b3aff77 100644 --- a/home-manager/config/firefox/chrome/userChrome.css +++ b/home-manager/config/firefox/config/chrome/userChrome.css diff --git a/home-manager/config/firefox/settings/extensions.json b/home-manager/config/firefox/config/extensions/extensions.json index 1de32896..1de32896 100644 --- a/home-manager/config/firefox/settings/extensions.json +++ b/home-manager/config/firefox/config/extensions/extensions.json diff --git a/home-manager/config/firefox/config/prefs/default.nix b/home-manager/config/firefox/config/prefs/default.nix new file mode 100644 index 00000000..d8dab86d --- /dev/null +++ b/home-manager/config/firefox/config/prefs/default.nix @@ -0,0 +1,73 @@ +# vim: ts=2 +{ + pkgs, + config, + user_js, + lib, + ... +}: let + bookmarks = import ../bookmarks; + firefoxBookmarksFile = (import ../../functions/bookmarks) {inherit lib pkgs;}; + user_js_override = pkgs.writeText "user.override.js" (builtins.readFile ./override.js); +in + pkgs.runCommand "user.js" {} '' + mkdir $out; + cat "${user_js}/user.js" > $out/user.js; + cat "${user_js_override}" >> $out/user.js; + + cat << EOF >> $out/user.js; + // My bookmarks + user_pref("browser.bookmarks.file", "${toString (firefoxBookmarksFile bookmarks)}"); + user_pref("browser.places.importBookmarksHTML", true); + + // Allow my custom css + user_pref("toolkit.legacyUserProfileCustomizations.stylesheets", true); + + // might improve performance TODO + user_pref("gfx.webrender.all", true); + + // disable updates (pretty pointless with nix) + user_pref("extensions.update.autoUpdateDefault", false); + user_pref("extensions.update.enabled", false); + user_pref("app.update.channel", "default"); + + user_pref("browser.ctrlTab.recentlyUsedOrder", false); + + user_pref("browser.download.useDownloadDir", true); + user_pref("browser.download.dir", "${config.home.homeDirectory}/media/downloads"); + user_pref("browser.download.folderList", 2); # TODO + user_pref("browser.download.viewableInternally.typeWasRegistered.svg", true); + user_pref("browser.download.viewableInternally.typeWasRegistered.webp", true); + user_pref("browser.download.viewableInternally.typeWasRegistered.xml", true); + + // TODO what does this do? + user_pref("browser.search.widget.inNavBar", true); + + user_pref("browser.shell.checkDefaultBrowser", false); + user_pref("browser.tabs.loadInBackground", true); + user_pref("browser.urlbar.placeholderName", "Brave"); + + // Set the tabs and bookmarks + user_pref("browser.tabs.inTitlebar", 1); + user_pref("browser.toolbars.bookmarks.visibility", "always"); + + // Theme + user_pref("extensions.activeThemeID", "firefox-alpenglow@mozilla.org"); + user_pref("extensions.extensions.activeThemeID", "firefox-alpenglow@mozilla.org"); + + // highlight all entries when searching + user_pref("findbar.highlightAll", true); + + // TODO + //user_pref("extensions.webcompat.enable_picture_in_picture_overrides", true); + //user_pref("extensions.webcompat.enable_shims", true); + //user_pref("extensions.webcompat.perform_injections", true); + //user_pref("extensions.webcompat.perform_ua_overrides", true); + + // onlykey / copied from a yubikey config + //user_pref("security.webauth.u2f", true); + //user_pref("security.webauth.webauthn", true); + //user_pref("security.webauth.webauthn_enable_softtoken", true); + //user_pref("security.webauth.webauthn_enable_usbtoken", true); + EOF + '' diff --git a/home-manager/config/firefox/settings/override.js b/home-manager/config/firefox/config/prefs/override.js index ca03e8ed..ca03e8ed 100644 --- a/home-manager/config/firefox/settings/override.js +++ b/home-manager/config/firefox/config/prefs/override.js diff --git a/home-manager/config/firefox/config/search/engines/default.nix b/home-manager/config/firefox/config/search/engines/default.nix new file mode 100644 index 00000000..286d7247 --- /dev/null +++ b/home-manager/config/firefox/config/search/engines/default.nix @@ -0,0 +1,59 @@ +{pkgs, ...}: { + "Brave Search" = { + urls = [{template = "https://search.brave.com/search?q={searchTerms}";}]; + IconUpdateURL = "https://raw.githubusercontent.com/brave/brave-core/master/components/brave_welcome_ui/components/images/lion_logo.svg"; + updateInterval = 24; # every day + definedAliases = ["@bs"]; + }; + + # NIX + "Nix Packages" = { + urls = [{template = "https://search.nixos.org/packages?type=packages&query={searchTerms}";}]; + icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; + definedAliases = ["@np"]; + }; + "Nix Options" = { + urls = [{template = "https://search.nixos.org/options?type=options&query={searchTerms}";}]; + icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; + definedAliases = ["@no"]; + }; + "NixOS Wiki" = { + urls = [{template = "https://nixos.wiki/index.php?search={searchTerms}";}]; + icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; + definedAliases = ["@nw"]; + }; + + "Arch Wiki" = { + urls = [{template = "https://wiki.archlinux.org/index.php?search={searchTerms}";}]; + iconUpdateURL = "https://upload.wikimedia.org/wikipedia/commons/a/a5/Archlinux-icon-crystal-64.svg"; + updateInterval = 24; + definedAliases = ["@aw"]; + }; + + # RUST + "Rust std" = { + urls = [{template = "https://doc.rust-lang.org/std/?search={searchTerms}";}]; + iconUpdateURL = "https://rustacean.net/assets/rustacean-orig-noshadow.svg"; + updateInterval = 24; + definedAliases = ["@rs"]; + }; + + "Google Scholar" = { + urls = [{template = "https://scholar.google.com/scholar?hl=en&q={searchTerms}";}]; + iconUpdateURL = "https://scholar.google.com/favicon.ico"; + updateInterval = 24; + definedAliases = ["@gs"]; + }; + "Wikipedia" = { + urls = [{template = "https://en.wikipedia.org/wiki/{searchTerms}";}]; + iconUpdateURL = "https://upload.wikimedia.org/wikipedia/en/8/80/Wikipedia-logo-v2.svg"; + updateInterval = 24; + definedAliases = ["@wp"]; + }; + + "Wikipedia (en)".metaData.hidden = true; + "DuckDuckGo".metaData.hidden = true; + "Bing".metaData.hidden = true; + "Google".metaData.hidden = true; + "Amazon.de".metaData.hidden = true; +} diff --git a/home-manager/config/firefox/default.nix b/home-manager/config/firefox/default.nix index 611f594c..0b98f5d6 100644 --- a/home-manager/config/firefox/default.nix +++ b/home-manager/config/firefox/default.nix @@ -7,192 +7,21 @@ video_pause, ... }: let - bookmarks = [ - { - name = "Feed - Piped"; - url = "https://piped.video/feed"; - } + userChrome = builtins.readFile ./config/chrome/userChrome.css; - { - name = "DeepL Translate"; - url = "https://www.deepl.com/translator#en/de/test"; - } - - { - name = "HM Options"; - url = "https://mipmip.github.io/home-manager-option-search/"; - } - ]; - firefoxBookmarksFile = bookmarks: let - indent = level: - lib.concatStringsSep "" (map (lib.const " ") (lib.range 1 level)); - - bookmarkToHTML = indentLevel: bookmark: '' - ${indent indentLevel}<DT><A HREF="${ - lib.escapeXML bookmark.url - }" ADD_DATE="0" LAST_MODIFIED="0">${lib.escapeXML bookmark.name}</A>''; - - directoryToHTML = indentLevel: directory: '' - ${indent indentLevel}<DT>${ - if directory.toolbar - then ''<H3 PERSONAL_TOOLBAR_FOLDER="true">Bookmarks Toolbar'' - else "<H3>${lib.escapeXML directory.name}" - }</H3> - ${indent indentLevel}<DL><p> - ${allItemsToHTML (indentLevel + 1) directory.bookmarks} - ${indent indentLevel}</p></DL>''; - - itemToHTMLOrRecurse = indentLevel: item: - if item ? "url" - then bookmarkToHTML indentLevel item - else directoryToHTML indentLevel item; - - allItemsToHTML = indentLevel: bookmarks: - lib.concatStringsSep "\n" - (map (itemToHTMLOrRecurse indentLevel) bookmarks); - - bookmarkEntries = allItemsToHTML 1 bookmarks; - in - pkgs.writeText "firefox-bookmarks.html" '' - <!DOCTYPE NETSCAPE-Bookmark-file-1> - <!-- This is an automatically generated file. - It will be read and overwritten. - DO NOT EDIT! --> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8"> - <TITLE>Bookmarks</TITLE> - <H1>Bookmarks Menu</H1> - - <DL><p> - <DT><H3 ADD_DATE="0" LAST_MODIFIED="0" PERSONAL_TOOLBAR_FOLDER="true">Bookmarks Toolbar</H3> - <DL><p> - ${bookmarkEntries} - </DL><p> - </p></DL> - ''; - userChrome = builtins.readFile ./chrome/userChrome.css; - - user_js_override = pkgs.writeText "user.override.js" (builtins.readFile ./settings/override.js); - user_js_nix = pkgs.runCommand "user.js" {} '' - mkdir $out; - cat "${user_js}/user.js" > $out/user.js; - cat "${user_js_override}" >> $out/user.js; - - cat << EOF >> $out/user.js; - // My bookmarks - user_pref("browser.bookmarks.file", "${toString (firefoxBookmarksFile bookmarks)}"); - user_pref("browser.places.importBookmarksHTML", true); - - // Allow my custom css - user_pref("toolkit.legacyUserProfileCustomizations.stylesheets", true); - - // might improve performance TODO - user_pref("gfx.webrender.all", true); - - // disable updates (pretty pointless with nix) - user_pref("extensions.update.autoUpdateDefault", false); - user_pref("extensions.update.enabled", false); - user_pref("app.update.channel", "default"); - - user_pref("browser.ctrlTab.recentlyUsedOrder", false); - - user_pref("browser.download.useDownloadDir", true); - user_pref("browser.download.dir", "${config.home.homeDirectory}/media/downloads"); - user_pref("browser.download.folderList", 2); # TODO - user_pref("browser.download.viewableInternally.typeWasRegistered.svg", true); - user_pref("browser.download.viewableInternally.typeWasRegistered.webp", true); - user_pref("browser.download.viewableInternally.typeWasRegistered.xml", true); - - // TODO what does this do? - user_pref("browser.search.widget.inNavBar", true); - - user_pref("browser.shell.checkDefaultBrowser", false); - user_pref("browser.tabs.loadInBackground", true); - user_pref("browser.urlbar.placeholderName", "Brave"); - - // Set the tabs and bookmarks - user_pref("browser.tabs.inTitlebar", 1); - user_pref("browser.toolbars.bookmarks.visibility", "always"); - - // Theme - user_pref("extensions.activeThemeID", "firefox-alpenglow@mozilla.org"); - user_pref("extensions.extensions.activeThemeID", "firefox-alpenglow@mozilla.org"); - - // highlight all entries when searching - user_pref("findbar.highlightAll", true); - - // TODO - //user_pref("extensions.webcompat.enable_picture_in_picture_overrides", true); - //user_pref("extensions.webcompat.enable_shims", true); - //user_pref("extensions.webcompat.perform_injections", true); - //user_pref("extensions.webcompat.perform_ua_overrides", true); - - // onlykey / copied from a yubikey config - //user_pref("security.webauth.u2f", true); - //user_pref("security.webauth.webauthn", true); - //user_pref("security.webauth.webauthn_enable_softtoken", true); - //user_pref("security.webauth.webauthn_enable_usbtoken", true); - EOF - ''; + user_js_nix = (import ./config/prefs) {inherit pkgs lib config user_js;}; extensions = builtins.map buildFirefoxXpiAddon ( lib.attrValues ( - lib.importJSON ./settings/extensions.json + lib.importJSON ./config/extensions/extensions.json ) ); + engines = (import ./config/search/engines) {inherit pkgs;}; # source: https://gitlab.com/rycee/nur-expressions/-/blob/master/pkgs/firefox-addons/default.nix - buildFirefoxXpiAddon = { - pname, - version, - addonId, - url, - sha256, - #meta, - ... - }: - pkgs.stdenv.mkDerivation { - name = "${pname}-${version}"; - - #inherit meta; - - src = builtins.fetchurl {inherit url sha256;}; - - preferLocalBuild = true; - allowSubstitutes = true; - - buildCommand = '' - dst="$out/share/mozilla/extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}" - mkdir -p "$dst" - install -v -m644 "$src" "$dst/${addonId}.xpi" - ''; - }; + buildFirefoxXpiAddon = (import ./functions/extensions) {inherit pkgs;}; - settings = {}; - video-pauser = pkgs.runCommand "video_pause_native_messaging" {} '' - install -d $out/share/ - cat << EOF > $out/share/video_pauser.json - { - "name": "video_pauser", - "description": "Pause your Videos with a single key stroke!", - "path": "${video_pause}/bin/video_pause", - "type": "stdio", - "allowed_extensions": ["video-pauser@addons.vhack.eu"] - } - EOF - - nativeMessagingPaths=( - /lib/mozilla/native-messaging-hosts - /etc/opt/chrome/native-messaging-hosts - /etc/chromium/native-messaging-hosts - /etc/vivaldi/native-messaging-hosts - /lib/librewolf/native-messaging-hosts - ) - - for manifestDir in "''${nativeMessagingPaths[@]}"; do - install -d $out$manifestDir - ln -s $out/share/video_pauser.json $out$manifestDir/ - done - ''; + video-pauser = (import ./functions/extensions/video-pauser.nix) {inherit pkgs video_pause;}; in { home.sessionVariables = { # improve touch input & make scrolling smother @@ -227,69 +56,10 @@ in { default = "Brave Search"; force = true; - engines = { - "Brave Search" = { - urls = [{template = "https://search.brave.com/search?q={searchTerms}";}]; - iconUpdateURL = "https://raw.githubusercontent.com/brave/brave-core/master/components/brave_welcome_ui/components/images/lion_logo.svg"; - updateInterval = 24; # every day - definedAliases = ["@bs"]; - }; - - # NIX - "Nix Packages" = { - urls = [{template = "https://search.nixos.org/packages?type=packages&query={searchTerms}";}]; - icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; - definedAliases = ["@np"]; - }; - "Nix Options" = { - urls = [{template = "https://search.nixos.org/options?type=options&query={searchTerms}";}]; - icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; - definedAliases = ["@no"]; - }; - "NixOS Wiki" = { - urls = [{template = "https://nixos.wiki/index.php?search={searchTerms}";}]; - icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; - definedAliases = ["@nw"]; - }; - - "Arch Wiki" = { - urls = [{template = "https://wiki.archlinux.org/index.php?search={searchTerms}";}]; - iconUpdateURL = "https://upload.wikimedia.org/wikipedia/commons/a/a5/Archlinux-icon-crystal-64.svg"; - updateInterval = 24; - definedAliases = ["@aw"]; - }; - - # RUST - "Rust std" = { - urls = [{template = "https://doc.rust-lang.org/std/?search={searchTerms}";}]; - iconUpdateURL = "https://rustacean.net/assets/rustacean-orig-noshadow.svg"; - updateInterval = 24; - definedAliases = ["@rs"]; - }; - - "Google Scholar" = { - urls = [{template = "https://scholar.google.com/scholar?hl=en&q={searchTerms}";}]; - iconUpdateURL = "https://scholar.google.com/favicon.ico"; - updateInterval = 24; - definedAliases = ["@gs"]; - }; - "Wikipedia" = { - urls = [{template = "https://en.wikipedia.org/wiki/{searchTerms}";}]; - iconUpdateURL = "https://upload.wikimedia.org/wikipedia/en/8/80/Wikipedia-logo-v2.svg"; - updateInterval = 24; - definedAliases = ["@wp"]; - }; - - "Wikipedia (en)".metaData.hidden = true; - "DuckDuckGo".metaData.hidden = true; - "Bing".metaData.hidden = true; - "Google".metaData.hidden = true; - "Amazon.de".metaData.hidden = true; - }; + inherit engines; }; bookmarks = []; - inherit settings; extraConfig = builtins.readFile "${user_js_nix}/user.js"; }; }; diff --git a/home-manager/config/firefox/functions/bookmarks/default.nix b/home-manager/config/firefox/functions/bookmarks/default.nix new file mode 100644 index 00000000..d1d89dd2 --- /dev/null +++ b/home-manager/config/firefox/functions/bookmarks/default.nix @@ -0,0 +1,49 @@ +{ + lib, + pkgs, +}: bookmarks: let + indent = level: + lib.concatStringsSep "" (map (lib.const " ") (lib.range 1 level)); + + bookmarkToHTML = indentLevel: bookmark: '' + ${indent indentLevel}<DT><A HREF="${ + lib.escapeXML bookmark.url + }" ADD_DATE="0" LAST_MODIFIED="0">${lib.escapeXML bookmark.name}</A>''; + + directoryToHTML = indentLevel: directory: '' + ${indent indentLevel}<DT>${ + if directory.toolbar + then ''<H3 PERSONAL_TOOLBAR_FOLDER="true">Bookmarks Toolbar'' + else "<H3>${lib.escapeXML directory.name}" + }</H3> + ${indent indentLevel}<DL><p> + ${allItemsToHTML (indentLevel + 1) directory.bookmarks} + ${indent indentLevel}</p></DL>''; + + itemToHTMLOrRecurse = indentLevel: item: + if item ? "url" + then bookmarkToHTML indentLevel item + else directoryToHTML indentLevel item; + + allItemsToHTML = indentLevel: bookmarks: + lib.concatStringsSep "\n" + (map (itemToHTMLOrRecurse indentLevel) bookmarks); + + bookmarkEntries = allItemsToHTML 1 bookmarks; +in + pkgs.writeText "firefox-bookmarks.html" '' + <!DOCTYPE NETSCAPE-Bookmark-file-1> + <!-- This is an automatically generated file. + It will be read and overwritten. + DO NOT EDIT! --> + <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8"> + <TITLE>Bookmarks</TITLE> + <H1>Bookmarks Menu</H1> + + <DL><p> + <DT><H3 ADD_DATE="0" LAST_MODIFIED="0" PERSONAL_TOOLBAR_FOLDER="true">Bookmarks Toolbar</H3> + <DL><p> + ${bookmarkEntries} + </DL><p> + </p></DL> + '' diff --git a/home-manager/config/firefox/functions/extensions/default.nix b/home-manager/config/firefox/functions/extensions/default.nix new file mode 100644 index 00000000..e3373d86 --- /dev/null +++ b/home-manager/config/firefox/functions/extensions/default.nix @@ -0,0 +1,26 @@ +# vim: ts=2 +{pkgs, ...}: { + pname, + version, + addonId, + url, + sha256, + #meta, + ... +}: +pkgs.stdenv.mkDerivation { + name = "${pname}-${version}"; + + #inherit meta; + + src = builtins.fetchurl {inherit url sha256;}; + + preferLocalBuild = true; + allowSubstitutes = true; + + buildCommand = '' + dst="$out/share/mozilla/extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}" + mkdir -p "$dst" + install -v -m644 "$src" "$dst/${addonId}.xpi" + ''; +} diff --git a/home-manager/config/firefox/functions/extensions/video-pauser.nix b/home-manager/config/firefox/functions/extensions/video-pauser.nix new file mode 100644 index 00000000..a6b0e838 --- /dev/null +++ b/home-manager/config/firefox/functions/extensions/video-pauser.nix @@ -0,0 +1,31 @@ +# vim: ts=2 +{ + pkgs, + video_pause, + ... +}: +pkgs.runCommand "video_pause_native_messaging" {} '' + install -d $out/share/ + cat << EOF > $out/share/video_pauser.json + { + "name": "video_pauser", + "description": "Pause your Videos with a single key stroke!", + "path": "${video_pause}/bin/video_pause", + "type": "stdio", + "allowed_extensions": ["video-pauser@addons.vhack.eu"] + } + EOF + + nativeMessagingPaths=( + /lib/mozilla/native-messaging-hosts + /etc/opt/chrome/native-messaging-hosts + /etc/chromium/native-messaging-hosts + /etc/vivaldi/native-messaging-hosts + /lib/librewolf/native-messaging-hosts + ) + + for manifestDir in "''${nativeMessagingPaths[@]}"; do + install -d $out$manifestDir + ln -s $out/share/video_pauser.json $out$manifestDir/ + done +'' diff --git a/home-manager/config/firefox/scripts/update_extensions b/home-manager/config/firefox/scripts/update_extensions index b743f4f1..2c532387 100755 --- a/home-manager/config/firefox/scripts/update_extensions +++ b/home-manager/config/firefox/scripts/update_extensions @@ -15,7 +15,7 @@ cat << EOF > $tmp EOF -nix shell git+https://codeberg.org/ene/generate_moz_extension.git -c generate_extensions $(cat $tmp) > "$(dirname $0)"/../settings/extensions.json +nix shell git+https://codeberg.org/ene/generate_moz_extension.git -c generate_extensions $(cat $tmp) > "$(dirname $0)"/../config/extensions/extensions.json |