mirror of
https://github.com/nix-community/home-manager.git
synced 2025-11-08 11:36:05 +01:00
firefox: new permission checks for extensions
Add two new options to customize how extension permissions are checked: - `extensions.exhaustivePermissions` Ensures that the permissions requested by all extensions managed by home-manager are authorized - `extensions.exactPermissions` When enabled, the user must authorize only the permissions that the extensions requests, not more nor less.
This commit is contained in:
parent
b27e551270
commit
c7f4214fac
4 changed files with 306 additions and 20 deletions
|
|
@ -704,6 +704,35 @@ in
|
|||
type = types.bool;
|
||||
};
|
||||
|
||||
exhaustivePermissions = mkOption {
|
||||
description = ''
|
||||
When enabled, the user must authorize requested
|
||||
permissions for all extensions from
|
||||
{option}`${moduleName}.profiles.<profile>.extensions.packages`
|
||||
in
|
||||
{option}`${moduleName}.profiles.<profile>.extensions.settings.<extensionID>.permissions`
|
||||
'';
|
||||
default = false;
|
||||
example = true;
|
||||
type = types.bool;
|
||||
};
|
||||
|
||||
exactPermissions = mkOption {
|
||||
description = ''
|
||||
When enabled,
|
||||
{option}`${moduleName}.profiles.<profile>.extensions.settings.<extensionID>.permissions`
|
||||
must specify the exact set of permissions that the
|
||||
extension will request.
|
||||
|
||||
This means that if the authorized permissions are
|
||||
broader than what the extension requests, the
|
||||
assertion will fail.
|
||||
'';
|
||||
default = false;
|
||||
example = true;
|
||||
type = types.bool;
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
default = { };
|
||||
example = literalExpression ''
|
||||
|
|
@ -800,12 +829,63 @@ in
|
|||
'';
|
||||
}
|
||||
]
|
||||
++ (builtins.concatMap (
|
||||
{ addonId, meta, ... }:
|
||||
let
|
||||
permissions = config.extensions.settings.${addonId}.permissions or null;
|
||||
requireCheck = config.extensions.exhaustivePermissions || permissions != null;
|
||||
authorizedPermissions = lib.optionals (permissions != null) permissions;
|
||||
missingPermissions = lib.subtractLists authorizedPermissions meta.mozPermissions;
|
||||
redundantPermissions = lib.subtractLists meta.mozPermissions authorizedPermissions;
|
||||
checkSatisfied =
|
||||
if config.extensions.exactPermissions then
|
||||
missingPermissions == [ ] && redundantPermissions == [ ]
|
||||
else
|
||||
missingPermissions == [ ];
|
||||
errorMessage =
|
||||
if
|
||||
config.extensions.exactPermissions && missingPermissions != [ ] && redundantPermissions != [ ]
|
||||
then
|
||||
''
|
||||
Extension ${addonId} requests permissions that weren't
|
||||
authorized: ${builtins.toJSON missingPermissions}.
|
||||
Additionally, the following permissions were authorized,
|
||||
but extension ${addonId} did not request them:
|
||||
${builtins.toJSON redundantPermissions}.
|
||||
Consider adjusting the permissions in''
|
||||
else if config.extensions.exactPermissions && redundantPermissions != [ ] then
|
||||
''
|
||||
The following permissions were authorized, but extension
|
||||
${addonId} did not request them: ${builtins.toJSON redundantPermissions}.
|
||||
Consider removing the redundant permissions from''
|
||||
else
|
||||
''
|
||||
Extension ${addonId} requests permissions that weren't
|
||||
authorized: ${builtins.toJSON missingPermissions}.
|
||||
Consider adding the missing permissions to'';
|
||||
in
|
||||
[
|
||||
{
|
||||
assertion = !requireCheck || checkSatisfied;
|
||||
message = ''
|
||||
${errorMessage}
|
||||
'${
|
||||
lib.showAttrPath (
|
||||
profilePath
|
||||
++ [
|
||||
"extensions"
|
||||
addonId
|
||||
]
|
||||
)
|
||||
}.permissions'.
|
||||
'';
|
||||
}
|
||||
]
|
||||
) config.extensions.packages)
|
||||
++ (builtins.concatMap (
|
||||
{ name, value }:
|
||||
let
|
||||
packages = builtins.filter (pkg: pkg.addonId == name) config.extensions.packages;
|
||||
package = builtins.head packages;
|
||||
unauthorized = lib.subtractLists value.permissions package.meta.mozPermissions;
|
||||
in
|
||||
[
|
||||
{
|
||||
|
|
@ -815,24 +895,6 @@ in
|
|||
in '${lib.showOption profilePath}.extensions.packages' but found ${toString (length packages)}.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
assertion = value.permissions == null || length packages != 1 || unauthorized == [ ];
|
||||
message = ''
|
||||
Extension ${name} requests permissions that weren't
|
||||
authorized: ${builtins.toJSON unauthorized}.
|
||||
Consider adding the missing permissions to
|
||||
'${
|
||||
lib.showAttrPath (
|
||||
profilePath
|
||||
++ [
|
||||
"extensions"
|
||||
name
|
||||
]
|
||||
)
|
||||
}.permissions'.
|
||||
'';
|
||||
}
|
||||
]
|
||||
) (lib.attrsToList config.extensions.settings))
|
||||
++ config.bookmarks.assertions;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ builtins.mapAttrs
|
|||
"${name}-profiles-duplicate-ids" = ./profiles/duplicate-ids.nix;
|
||||
"${name}-profiles-extensions" = ./profiles/extensions;
|
||||
"${name}-profiles-extensions-assertions" = ./profiles/extensions/assertions.nix;
|
||||
"${name}-profiles-extensions-exhaustive" = ./profiles/extensions/exhaustive.nix;
|
||||
"${name}-profiles-extensions-exact" = ./profiles/extensions/exact.nix;
|
||||
"${name}-profiles-overwrite" = ./profiles/overwrite;
|
||||
"${name}-profiles-search" = ./profiles/search;
|
||||
"${name}-profiles-settings" = ./profiles/settings;
|
||||
|
|
|
|||
130
tests/modules/programs/firefox/profiles/extensions/exact.nix
Normal file
130
tests/modules/programs/firefox/profiles/extensions/exact.nix
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
modulePath:
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
|
||||
firefoxMockOverlay = import ../../setup-firefox-mock-overlay.nix modulePath;
|
||||
|
||||
uBlockStubPkg = config.lib.test.mkStubPackage {
|
||||
name = "ublock-origin-dummy";
|
||||
extraAttrs = {
|
||||
addonId = "uBlock0@raymondhill.net";
|
||||
meta.mozPermissions = [
|
||||
"privacy"
|
||||
"storage"
|
||||
"tabs"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
sponsorBlockStubPkg = config.lib.test.mkStubPackage {
|
||||
name = "sponsorblock";
|
||||
extraAttrs = {
|
||||
addonId = "sponsorBlocker@ajay.app";
|
||||
meta.mozPermissions = [
|
||||
"storage"
|
||||
"scripting"
|
||||
"https://sponsor.ajay.app/*"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
noscriptStubPkg = config.lib.test.mkStubPackage {
|
||||
name = "noscript";
|
||||
extraAttrs = {
|
||||
addonId = "{73a6fe31-595d-460b-a920-fcc0f8843232}";
|
||||
meta.mozPermissions = [
|
||||
"contextMenus"
|
||||
"storage"
|
||||
"tabs"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
bitwardenStubPkg = config.lib.test.mkStubPackage {
|
||||
name = "bitwarden";
|
||||
extraAttrs = {
|
||||
addonId = "{446900e4-71c2-419f-a6a7-df9c091e268b}";
|
||||
meta.mozPermissions = [
|
||||
"webNavigation"
|
||||
"webRequest"
|
||||
"webRequestBlocking"
|
||||
];
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
imports = [ firefoxMockOverlay ];
|
||||
|
||||
config = lib.mkIf config.test.enableBig (
|
||||
lib.setAttrByPath modulePath {
|
||||
enable = true;
|
||||
profiles.extensions = {
|
||||
extensions = {
|
||||
packages = [
|
||||
uBlockStubPkg
|
||||
sponsorBlockStubPkg
|
||||
noscriptStubPkg
|
||||
bitwardenStubPkg
|
||||
];
|
||||
exactPermissions = true;
|
||||
settings = {
|
||||
${uBlockStubPkg.addonId} = {
|
||||
permissions = [
|
||||
"privacy"
|
||||
"storage"
|
||||
];
|
||||
};
|
||||
${sponsorBlockStubPkg.addonId} = {
|
||||
permissions = [
|
||||
"storage"
|
||||
"scripting"
|
||||
"https://sponsor.ajay.app/*"
|
||||
"<all_urls>"
|
||||
];
|
||||
};
|
||||
${noscriptStubPkg.addonId} = {
|
||||
permissions = [
|
||||
"storage"
|
||||
"tabs"
|
||||
"https://github.com/*"
|
||||
];
|
||||
};
|
||||
${bitwardenStubPkg.addonId} = {
|
||||
permissions = [
|
||||
"webNavigation"
|
||||
"webRequest"
|
||||
"webRequestBlocking"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
// {
|
||||
test.asserts.assertions.expected = [
|
||||
''
|
||||
Extension ${uBlockStubPkg.addonId} requests permissions that weren't
|
||||
authorized: ["tabs"].
|
||||
Consider adding the missing permissions to
|
||||
'${lib.showOption modulePath}.profiles.extensions.extensions."${uBlockStubPkg.addonId}".permissions'.
|
||||
''
|
||||
''
|
||||
The following permissions were authorized, but extension
|
||||
${sponsorBlockStubPkg.addonId} did not request them: ["<all_urls>"].
|
||||
Consider removing the redundant permissions from
|
||||
'${lib.showOption modulePath}.profiles.extensions.extensions."${sponsorBlockStubPkg.addonId}".permissions'.
|
||||
''
|
||||
''
|
||||
Extension ${noscriptStubPkg.addonId} requests permissions that weren't
|
||||
authorized: ["contextMenus"].
|
||||
Additionally, the following permissions were authorized,
|
||||
but extension ${noscriptStubPkg.addonId} did not request them:
|
||||
["https://github.com/*"].
|
||||
Consider adjusting the permissions in
|
||||
'${lib.showOption modulePath}.profiles.extensions.extensions."${noscriptStubPkg.addonId}".permissions'.
|
||||
''
|
||||
];
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
modulePath:
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
|
||||
firefoxMockOverlay = import ../../setup-firefox-mock-overlay.nix modulePath;
|
||||
|
||||
uBlockStubPkg = config.lib.test.mkStubPackage {
|
||||
name = "ublock-origin-dummy";
|
||||
extraAttrs = {
|
||||
addonId = "uBlock0@raymondhill.net";
|
||||
meta.mozPermissions = [
|
||||
"<all_urls>"
|
||||
"http://*/*"
|
||||
"https://github.com/*"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
sponsorBlockStubPkg = config.lib.test.mkStubPackage {
|
||||
name = "sponsorblock";
|
||||
extraAttrs = {
|
||||
addonId = "sponsorBlocker@ajay.app";
|
||||
meta.mozPermissions = [
|
||||
"storage"
|
||||
"scripting"
|
||||
"https://sponsor.ajay.app/*"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
noscriptStubPkg = config.lib.test.mkStubPackage {
|
||||
name = "noscript";
|
||||
extraAttrs = {
|
||||
addonId = "{73a6fe31-595d-460b-a920-fcc0f8843232}";
|
||||
meta.mozPermissions = [
|
||||
"contextMenus"
|
||||
"storage"
|
||||
"tabs"
|
||||
];
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
imports = [ firefoxMockOverlay ];
|
||||
|
||||
config = lib.mkIf config.test.enableBig (
|
||||
lib.setAttrByPath modulePath {
|
||||
enable = true;
|
||||
profiles.extensions = {
|
||||
extensions = {
|
||||
packages = [
|
||||
uBlockStubPkg
|
||||
sponsorBlockStubPkg
|
||||
noscriptStubPkg
|
||||
];
|
||||
exhaustivePermissions = true;
|
||||
settings = {
|
||||
${uBlockStubPkg.addonId} = {
|
||||
permissions = [
|
||||
"<all_urls>"
|
||||
"http://*/*"
|
||||
"https://github.com/*"
|
||||
];
|
||||
};
|
||||
${noscriptStubPkg.addonId} = {
|
||||
permissions = [
|
||||
"contextMenus"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
// {
|
||||
test.asserts.assertions.expected = [
|
||||
''
|
||||
Extension ${sponsorBlockStubPkg.addonId} requests permissions that weren't
|
||||
authorized: ["storage","scripting","https://sponsor.ajay.app/*"].
|
||||
Consider adding the missing permissions to
|
||||
'${lib.showOption modulePath}.profiles.extensions.extensions."${sponsorBlockStubPkg.addonId}".permissions'.
|
||||
''
|
||||
''
|
||||
Extension ${noscriptStubPkg.addonId} requests permissions that weren't
|
||||
authorized: ["storage","tabs"].
|
||||
Consider adding the missing permissions to
|
||||
'${lib.showOption modulePath}.profiles.extensions.extensions."${noscriptStubPkg.addonId}".permissions'.
|
||||
''
|
||||
];
|
||||
}
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue