view release on metacpan or search on metacpan
- Adding --issuer-organization, --trusted-only and --profile-name options to ./ca-bundle-for-firefox
- Hiding bookmarks toolbar
1.28 Mon Jun 13 11:54 2022
- Adding ./setup-for-firefox-marionette-build.sh to remove the snap firefox for Ubuntu 22.04 TLS.
1.27 Sun May 08 21:38 2022
- Fixing missing META information
1.26 Sun May 01 06:31 2022
- Adding support for about:config prefs.js dynamic changes
1.25 Mon Apr 25 09:32 2022
- Adding X11 Forwarding and support for ssh jump hosts
- Reduce network and disk load during 'make test'
- Improving test suite (coverage now > 90%)
1.24 Fri Apr 8 19:32 2022
- Fixes for CPAN Testers results
- Adding visible support for remote Firefox instances on linux (via xvfb-run)
- Test suite changes for darwin
lib/Firefox/Marionette.pm view on Meta::CPAN
sub languages {
my ( $self, @new_languages ) = @_;
my $pref_name = 'intl.accept_languages';
my $script =
'return navigator.languages || branch.getComplexValue(arguments[0], Components.interfaces.nsIPrefLocalizedString).data.split(/,\s*/)';
my $old = $self->_context('chrome');
my @old_languages = @{
$self->script(
$self->_compress_script(
$self->_prefs_interface_preamble() . $script
),
args => [$pref_name]
)
};
$self->_context($old);
if ( scalar @new_languages ) {
$self->set_pref( $pref_name, join q[, ], @new_languages );
}
return @old_languages;
}
lib/Firefox/Marionette.pm view on Meta::CPAN
"speed": response["coords"]["speed"],
}; }).catch((err) => { throw err.message });
})();
_JS_
if ( ( defined $result ) && ( !ref $result ) ) {
Firefox::Marionette::Exception->throw("javascript error: $result");
}
return $result;
}
sub _prefs_interface_preamble {
my ($self) = @_;
return <<'_JS_'; # modules/libpref/nsIPrefService.idl
let prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
let branch = prefs.getBranch("");
_JS_
}
sub get_pref {
my ( $self, $name ) = @_;
my $script = <<'_JS_';
let result = [ null ];
switch (branch.getPrefType(arguments[0])) {
case branch.PREF_STRING:
result = [ branch.getStringPref ? branch.getStringPref(arguments[0]) : branch.getComplexValue(arguments[0], Components.interfaces.nsISupportsString).data, 'string' ];
lib/Firefox/Marionette.pm view on Meta::CPAN
break;
case branch.PREF_BOOL:
result = [ branch.getBoolPref(arguments[0]), 'boolean' ];
}
return result;
_JS_
my $old = $self->_context('chrome');
my ( $result, $type ) = @{
$self->script(
$self->_compress_script(
$self->_prefs_interface_preamble() . $script
),
args => [$name]
)
};
$self->_context($old);
if ($type) {
if ( $type eq 'integer' ) {
$result += 0;
}
}
lib/Firefox/Marionette.pm view on Meta::CPAN
branch.setStringPref(arguments[0], arguments[1]);
} else {
let newString = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);
newString.data = arguments[1];
branch.setComplexValue(arguments[0], Components.interfaces.nsISupportsString, newString);
}
}
_JS_
my $old = $self->_context('chrome');
$self->script(
$self->_compress_script( $self->_prefs_interface_preamble() . $script ),
args => [ $name, $value ]
);
$self->_context($old);
return $self;
}
sub _clear_data_service_interface_preamble {
my ($self) = @_;
return <<'_JS_'; # toolkit/components/cleardata/nsIClearDataService.idl
let clearDataService = Components.classes["@mozilla.org/clear-data-service;1"].getService(Components.interfaces.nsIClearDataService);
lib/Firefox/Marionette.pm view on Meta::CPAN
return $self;
}
sub clear_pref {
my ( $self, $name ) = @_;
my $script = <<'_JS_';
branch.clearUserPref(arguments[0]);
_JS_
my $old = $self->_context('chrome');
$self->script(
$self->_compress_script( $self->_prefs_interface_preamble() . $script ),
args => [$name]
);
$self->_context($old);
return $self;
}
sub _is_chrome_user_agent {
my ( $self, $user_agent ) = @_;
if ( $user_agent =~ /Chrome/smx ) {
return 1;
lib/Firefox/Marionette.pm view on Meta::CPAN
$self->{_ssh_local_directory} = $ssh_local_directory;
$self->{_root_directory} = $proxy->{ssh}->{root};
$self->{_remote_root_directory} = $proxy->{ssh}->{root};
if ( defined $proxy->{ssh}->{tmp} ) {
$self->{_original_remote_tmp_directory} =
$proxy->{ssh}->{tmp};
}
$self->{profile_path} =
$self->_remote_catfile( $self->{_root_directory},
'profile', 'prefs.js' );
my $local_scp_directory =
File::Spec->catdir( $self->ssh_local_directory(), 'scp' );
$self->{_local_scp_get_directory} =
File::Spec->catdir( $local_scp_directory, 'get' );
$self->{_scp_get_file_index} =
$self->_get_max_scp_file_index(
$self->{_local_scp_get_directory} );
$self->{_local_scp_put_directory} =
File::Spec->catdir( $local_scp_directory, 'put' );
lib/Firefox/Marionette.pm view on Meta::CPAN
push @{ $self->{mime_types} }, $mime_type;
$known_mime_types{$mime_type} = 1;
}
}
return;
}
sub _check_for_existing_local_firefox_process {
my ($self) = @_;
my $profile_path =
File::Spec->catfile( $self->{_profile_directory}, 'prefs.js' );
my $profile_handle = FileHandle->new($profile_path);
my $port;
if ($profile_handle) {
while ( my $line = <$profile_handle> ) {
if ( $line =~ /^user_pref[(]"marionette[.]port",[ ](\d+)[)];$/smx )
{
($port) = ($1);
}
}
}
lib/Firefox/Marionette.pm view on Meta::CPAN
"Failed to close directory '$temp_directory':$EXTENDED_OS_ERROR");
return $alive_pid;
}
sub _setup_profile {
my ($self) = @_;
if ( $self->{profile_name} ) {
$self->{_profile_directory} =
Firefox::Marionette::Profile->directory( $self->{profile_name} );
$self->{profile_path} =
File::Spec->catfile( $self->{_profile_directory}, 'prefs.js' );
}
else {
$self->{_profile_directory} =
File::Spec->catfile( $self->{_root_directory}, 'profile' );
$self->{_download_directory} =
File::Spec->catfile( $self->{_root_directory}, 'downloads' );
$self->{profile_path} =
File::Spec->catfile( $self->{_profile_directory}, 'prefs.js' );
}
return;
}
sub _reconnect {
my ( $self, %parameters ) = @_;
if ( $parameters{profile_name} ) {
$self->{profile_name} = $parameters{profile_name};
}
$self->{_reconnected} = 1;
lib/Firefox/Marionette.pm view on Meta::CPAN
_MILLISECONDS_IN_ONE_SECOND(),
implicit => $timeouts->implicit(),
page_load => $timeouts->page_load()
);
$self->timeouts($update_timeouts);
my $old = $self->_context('chrome');
# toolkit/mozapps/update/nsIUpdateService.idl
my $update_parameters = $self->script(
$self->_compress_script(
$self->_prefs_interface_preamble() . <<'_JS_' ) );
let disabledForTesting = branch.getBoolPref("app.update.disabledForTesting");
branch.setBoolPref("app.update.disabledForTesting", false);
let updateManager = new Promise((resolve, reject) => {
var updateStatus = {};
if ("@mozilla.org/updates/update-manager;1" in Components.classes) {
let PREF_APP_UPDATE_CANCELATIONS_OSX = "app.update.cancelations.osx";
let PREF_APP_UPDATE_ELEVATE_NEVER = "app.update.elevate.never";
if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CANCELATIONS_OSX)) {
Services.prefs.clearUserPref(PREF_APP_UPDATE_CANCELATIONS_OSX);
}
if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_ELEVATE_NEVER)) {
Services.prefs.clearUserPref(PREF_APP_UPDATE_ELEVATE_NEVER);
}
let updateService = Components.classes["@mozilla.org/updates/update-service;1"].getService(Components.interfaces.nsIApplicationUpdateService);
let latestUpdate = null;
if (!updateService.canCheckForUpdates) {
updateStatus["updateStatusCode"] = 'CANNOT_CHECK_FOR_UPDATES';
reject(updateStatus);
}
if (!updateService.canApplyUpdates) {
updateStatus["updateStatusCode"] = 'CANNOT_APPLY_UPDATES';
reject(updateStatus);
lib/Firefox/Marionette.pm view on Meta::CPAN
else {
$profile_ini_directory =
$self->_remote_catfile( '.mozilla', 'firefox' );
}
my $profile_ini_path =
$self->_remote_catfile( $profile_ini_directory, 'profiles.ini' );
my $handle = $self->_get_file_via_scp( { ignore_exit_status => 1 },
$profile_ini_path, 'profiles.ini file' )
or Firefox::Marionette::Exception->throw( 'Failed to find the file '
. $self->_ssh_address()
. ":$profile_ini_path which would indicate where the prefs.js file for the '$profile_name' is stored"
);
my $config = Config::INI::Reader->read_handle($handle);
$profile_directory = $self->_remote_catfile(
Firefox::Marionette::Profile->directory(
$profile_name, $config,
$profile_ini_directory, $self->_ssh_address()
)
);
}
return $profile_directory;
lib/Firefox/Marionette.pm view on Meta::CPAN
'-profile', $self->_restart_profile_directory(),
'--no-remote', '--new-instance'
);
}
elsif ( $parameters{profile_name} ) {
$self->{profile_name} = $parameters{profile_name};
if ( $self->_ssh() ) {
$self->{_profile_directory} =
$self->_get_remote_profile_directory( $parameters{profile_name} );
$self->{profile_path} =
$self->_remote_catfile( $self->{_profile_directory}, 'prefs.js' );
}
else {
$self->{_profile_directory} =
Firefox::Marionette::Profile->directory(
$parameters{profile_name} );
$self->{profile_path} =
File::Spec->catfile( $self->{_profile_directory}, 'prefs.js' );
}
push @arguments, ( '-P', $self->{profile_name} );
}
else {
my $profile_directory =
$self->_setup_new_profile( $parameters{profile}, %parameters );
if ( $self->_ssh() ) {
if ( $self->_remote_uname() eq 'cygwin' ) {
$profile_directory =
$self->_execute_via_ssh( {}, 'cygpath', '-s', '-m',
lib/Firefox/Marionette.pm view on Meta::CPAN
"Failed to create directory $tmp_directory:$EXTENDED_OS_ERROR");
}
return;
}
sub _new_profile_path {
my ($self) = @_;
my $profile_path;
if ( $self->_ssh() ) {
$profile_path =
$self->_remote_catfile( $self->{_profile_directory}, 'prefs.js' );
}
else {
$profile_path =
File::Spec->catfile( $self->{_profile_directory}, 'prefs.js' );
}
return $profile_path;
}
sub _setup_new_profile {
my ( $self, $profile, %parameters ) = @_;
$self->_setup_profile_directories($profile);
$self->{profile_path} = $self->_new_profile_path();
if ($profile) {
if ( !$profile->download_directory() ) {
lib/Firefox/Marionette/Profile.pm view on Meta::CPAN
if ( defined $config->{$key}->{Name} ) {
push @names, $config->{$key}->{Name};
}
}
return @names;
}
sub path {
my ( $class, $name ) = @_;
if ( my $profile_directory = $class->directory($name) ) {
return File::Spec->catfile( $profile_directory, 'prefs.js' );
}
return;
}
sub _parse_config_for_path {
my ( $class, $name, $config, $profile_ini_directory ) = @_;
my @path;
my $first_key;
foreach my $key ( sort { $a cmp $b } keys %{$config} ) {
if ( ( !defined $first_key ) && ( defined $config->{$key}->{Name} ) ) {
lib/Firefox/Marionette/Profile.pm view on Meta::CPAN
$profile->set_value( 'privacy.fingerprintingProtection', 'true', 0 );
$profile->set_value( 'privacy.fingerprintingProtection.pbmode',
'true', 0 );
$profile->set_value( 'privacy.trackingprotection.enabled', 'true', 0 );
$profile->set_value(
'privacy.trackingprotection.fingerprinting.enabled',
'true', 0 );
$profile->set_value( 'privacy.trackingprotection.pbmode.enabled',
'false', 0 );
$profile->set_value( 'profile.enable_profile_migration', 'false', 0 );
$profile->set_value( 'services.sync.prefs.sync.browser.search.update',
'false', 0 );
$profile->set_value(
'services.sync.prefs.sync.privacy.trackingprotection.cryptomining.enabled',
'false', 0
);
$profile->set_value(
'services.sync.prefs.sync.privacy.trackingprotection.enabled',
'false', 0 );
$profile->set_value(
'services.sync.prefs.sync.privacy.trackingprotection.fingerprinting.enabled',
'false', 0
);
$profile->set_value(
'services.sync.prefs.sync.privacy.trackingprotection.pbmode.enabled',
'false', 0
);
$profile->set_value( 'signon.rememberSignons', 'false', 0 );
$profile->set_value( 'signon.management.page.breach-alerts.enabled',
'false', 0 );
$profile->set_value( 'toolkit.telemetry.archive.enabled', 'false', 0 );
$profile->set_value( 'toolkit.telemetry.enabled', 'false', 0 );
$profile->set_value( 'toolkit.telemetry.rejected', 'true', 0 );
$profile->set_value( 'toolkit.telemetry.server', q[], 1 );
$profile->set_value( 'toolkit.telemetry.unified', 'false', 0 );
lib/Firefox/Marionette/Profile.pm view on Meta::CPAN
}
return $self;
}
1; # Magic true value required at end of module
__END__
=head1 NAME
Firefox::Marionette::Profile - Represents a prefs.js Firefox Profile
=head1 VERSION
Version 1.70
=head1 SYNOPSIS
use Firefox::Marionette();
use v5.10;
lib/Firefox/Marionette/Profile.pm view on Meta::CPAN
# OR start a new browser with a copy of a specific existing profile
$profile = Firefox::Marionette::Profile->existing($profile_name);
$firefox = Firefox::Marionette->new(profile => $profile);
$firefox->quit();
}
=head1 DESCRIPTION
This module handles the implementation of a C<prefs.js> Firefox Profile
=head1 CONSTANTS
=head2 ANY_PORT
returns the port number for Firefox to listen on any port (0).
=head1 SUBROUTINES/METHODS
=head2 new
lib/Firefox/Marionette/Profile.pm view on Meta::CPAN
=head2 names
returns a list of existing profile names that this module can discover on the filesystem.
=head2 default_name
returns the default profile name.
=head2 directory
accepts a profile name and returns the directory path that contains the C<prefs.js> file.
=head2 download_directory
accepts a directory path that will contain downloaded files. Returns the previous value for download directory.
=head2 existing
accepts a profile name and returns a L<profile|Firefox::Marionette::Profile> object for that specified profile name.
=head2 parse
accepts a path as the parameter. This path should be to a C<prefs.js> file. Parses the file and returns it as a L<profile|Firefox::Marionette::Profile>.
=head2 parse_by_handle
accepts a filehandle as the parameter to a C<prefs.js> file. Parses the file and returns it as a L<profile|Firefox::Marionette::Profile>.
=head2 path
accepts a profile name and returns the corresponding path to the C<prefs.js> file.
=head2 profile_ini_directory
returns the base directory for profiles.
=head2 save
accepts a path as the parameter. Saves the current profile to this location.
=head2 as_string
lib/Firefox/Marionette/Profile.pm view on Meta::CPAN
=item C<< Failed to rename '%s' to '%s':%s >>
The module was unable to rename the named file to the second file. Something is seriously wrong with your environment.
=item C<< Failed to open '%s' for reading:%s >>
The module was unable to open the named file. Maybe your disk is full or the file permissions need to be changed?
=item C<< Failed to parse line '%s' >>
The module was unable to parse the line for a Firefox prefs.js configuration. This is probably a bug in this module's logic. Please report as described in the BUGS AND LIMITATIONS section below.
=back
=head1 CONFIGURATION AND ENVIRONMENT
Firefox::Marionette::Profile requires no configuration files or environment variables.
=head1 DEPENDENCIES
Firefox::Marionette::Profile requires the following non-core Perl modules
lib/Waterfox/Marionette/Profile.pm view on Meta::CPAN
}
return $profile;
}
1; # Magic true value required at end of module
__END__
=head1 NAME
Waterfox::Marionette::Profile - Represents a prefs.js Waterfox Profile
=head1 VERSION
Version 1.70
=head1 SYNOPSIS
use Waterfox::Marionette();
use v5.10;
lib/Waterfox/Marionette/Profile.pm view on Meta::CPAN
# OR start a new browser with a copy of a specific existing profile
$profile = Waterfox::Marionette::Profile->existing($profile_name);
$firefox = Waterox::Marionette->new(profile => $profile);
$firefox->quit();
}
=head1 DESCRIPTION
This module handles the implementation of a C<prefs.js> Waterfox Profile. This module inherits from L<Firefox::Marionette::Profile|Firefox::Marionette::Profile>.
=head1 SUBROUTINES/METHODS
For a full list of methods available, see L<Firefox::Marionette::Profile|Firefox::Marionette::Profile#SUBROUTINES/METHODS>
=head2 new
returns a new L<profile|Waterfox::Marionette::Profile>.
=head2 profile_ini_directory
ssh-auth-cmd-marionette view on Meta::CPAN
%options = _validate_parameters(%options);
my ( $allowed_binary_directories_regex,
$allowed_binary_paths_regex, $allowed_binary_regex )
= _filesystem_regexes(%options);
my $sub_directory_regex = qr/(?:profile|downloads|tmp|addons|certs)/smx;
my $profile_names = q[(?:] . (
join q[|],
map { quotemeta } (
qw(
bookmarks.html
prefs.js
mimeTypes.rdf
search.json.mozlz4
)
)
) . q[)];
my $profile_file_regex = qr/profile\/$profile_names/smx;
my $file_regex = qr/[+\w\-()]{1,255}(?:[.][+\w\-()]{1,255})*/smx;
my $downloads_regex = qr/downloads\/$file_regex/smx;
my $addons_regex = qr/(?:addons|profile)\/$file_regex/smx;
my $ca_name_regex = qr/Firefox::Marionette[ ]Root[ ]CA/smx;
ssh-auth-cmd-marionette view on Meta::CPAN
qr/(?:[ ]\-height[ ]\d{1,8})?/smx,
qr/(?:[ ]\-\-jsconsole)?/smx,
qr/(?:[ ]\-MOZ_LOG=[[:alnum:],:]+)?/smx,
qr/(?:[ ]-safe\-mode)?/smx,
qr/(?:[ ]\-headless)?/smx,
qr/[ ](?:\-profile[ ]$root_dir_regex\/profile|\-P[ ][[:alnum:]]+)/smx,
qr/(?:[ ]\-\-no\-remote)?/smx,
qr/(?:[ ]\-\-new\-instance)?/smx,
qr/(?:[ ]\-\-devtools)?/smx,
qr/(?:[ ]\-\-kiosk)?/smx;
my $prefs_grep_patterns_regex = join q[],
qr/\-e[ ]marionette[ ]/smx,
qr/\-e[ ]security[ ]/smx;
my @darwin_regexes;
if ( $OSNAME eq 'darwin' ) {
my $plist_prefix_regex =
_get_plist_prefix_regex( @{ $options{'allow-binary'} } );
@darwin_regexes = (
qr/ls[ ]-1[ ]"$allowed_binary_regex"/smx,
qr/plutil[ ]-convert[ ]json[ ]-o[ ]-[ ]"(?:$plist_prefix_regex)\/Info[.]plist"/smx,
ssh-auth-cmd-marionette view on Meta::CPAN
qr/scp(?:[ ]\-v)?[ ]\-p[ ]\-[tf][ ]"?$root_dir_regex\/$downloads_regex"?/smx,
qr/scp[ ]\-p[ ]\-[tf][ ]"?$profiles_ini_regex"?/smx,
qr/kill[ ]\-0[ ]\d{1,8}/smx,
qr/which[ ]$allowed_binary_regex/smx,
qr/readlink[ ]\-f[ ]$allowed_binary_paths_regex/smx,
qr/rm[ ]\-Rf[ ]$root_dir_regex(?:[ ]$quoted_tmp_directory\/Temp\-[\d\-a-f]{1,255})*/smx,
qr/ls[ ]-1[ ]"$allowed_binary_directories_regex(?:\/updates(?:\/\d+)?)?"/smx,
qr/ls[ ]-1[ ]"$root_dir_regex\/downloads"/smx,
qr/certutil$certutil_arguments_regex/smx,
qr/(?:$xvfb_regex)?"$allowed_binary_regex"$firefox_arguments_regex/smx,
qr/grep[ ]$prefs_grep_patterns_regex$profile_path_regex\/prefs[.]js/smx;
my $user_name = getpwuid $EFFECTIVE_USER_ID;
if ( $ENV{SSH_ORIGINAL_COMMAND} =~ m/^($allowed_commands_regex)$/smx ) {
my ($command_and_arguments) = ($1);
if ( $options{'force-binary'} ) {
$command_and_arguments =~
s/^"$allowed_binary_regex"/"$options{'force-binary'}"/smx;
}
Sys::Syslog::openlog( $ident, 'cons', $options{facility} );
Sys::Syslog::syslog( Sys::Syslog::LOG_INFO(),
my $browser_version = "112.0.2";
if ($options{version}) {
$| = 1;
print "Mozilla Firefox $browser_version\n";
exit 0;
}
socket my $server, Socket::PF_INET(), Socket::SOCK_STREAM(), 0 or die "Failed to create a socket:$!";
bind $server, Socket::sockaddr_in( 0, Socket::INADDR_LOOPBACK() ) or die "Failed to bind socket:$!";
listen $server, Socket::SOMAXCONN() or die "Failed to listen:$!";
my $port = ( Socket::sockaddr_in( getsockname $server ) )[0];
my $prefs_path = File::Spec->catfile($options{profile}, 'prefs.js');
my $old_prefs_handle = FileHandle->new($prefs_path, Fcntl::O_RDONLY()) or die "Failed to open $prefs_path for reading:$!";
my $new_prefs_path = File::Spec->catfile($options{profile}, 'prefs.new');
my $new_prefs_handle = FileHandle->new($new_prefs_path, Fcntl::O_CREAT() | Fcntl::O_EXCL() | Fcntl::O_WRONLY(), Fcntl::S_IRUSR() | Fcntl::S_IWUSR()) or die "Failed to open $new_prefs_path for writing:$!";
while(my $line = <$old_prefs_handle>) {
if ($line =~ /^user_pref\("marionette.port",[ ]0\);/smx) {
print {$new_prefs_handle} qq[user_pref("marionette.port", $port);\n] or die "Failed to write to $new_prefs_path:$!";
} else {
print {$new_prefs_handle} $line or die "Failed to write to $new_prefs_path:$!";
}
}
close $new_prefs_handle or die "Failed to close $new_prefs_path:$!";
close $old_prefs_handle or die "Failed to close $prefs_path:$!";
rename $new_prefs_path, $prefs_path or die "Failed to rename $new_prefs_path to $prefs_path:$!";
my $paddr = accept(my $client, $server);
my $old = select $client; $| = 1; select $old;
syswrite $client, qq[50:{"applicationType":"gecko","marionetteProtocol":3}] or die "Failed to write to socket:$!";
my $request = _get_request($client);
my $platform = $^O;
my $headless = $options{headless} ? 'true' : 'false';
my $response_type = 1;
my $profile_path = $options{profile};
$profile_path =~ s/\\/\\\\/smxg;
my $capabilities = qq([1,1,null,{"sessionId":"5a5f9a08-0faa-4794-aa85-ee85980ce422","capabilities":{"browserName":"firefox","browserVersion":"$browser_version","platformName":"$platform","acceptInsecureCerts":false,"pageLoadStrategy":"normal","setWi...