<para>
To distinguish between the Android and the PC version, the website, issue tracker,
and code base refer to this version as <ulink url="https://www.stoutner.com/privacy-browser-pc/">Privacy Browser PC</ulink>.
- There is a list of feature requests and known bugs at <ulink url="https://redmine.stoutner.com/projects/privacy-browser-pc/issues">redmine.stoutner.com</ulink>.
- Users should anticipate that all the current features of <ulink url="https://www.stoutner.com/privacy-browser-android/">Privacy Browser Android</ulink>
- will also be implemented in Privacy Browser PC.
- There is no need at this point to create features requests for these as they will be added as I start working on each feature and have a better idea of how they will be implemented.
- However, each feature that has already been implemented should be bug free.
- If you discover a bug that is not already documented at <ulink url="https://redmine.stoutner.com/projects/privacy-browser-pc/issues">redmine.stoutner.com</ulink> please add it.
</para>
<para>
The best place to discuss the development of Privacy Browser is <ulink url="https://redmine.stoutner.com/projects/privacy-browser-pc/boards">on the forum</ulink>.
I also frequently post on my <ulink url="https://fosstodon.org/@privacybrowser">Mastodon account</ulink> regarding the development status.
</para>
+
+ <!-- Qt WebEngine. -->
+ <sect1 id="qt-webengine">
+ <title>Qt WebEngine</title>
+
+ <para>
+ Privacy Browser uses <ulink url="https://doc.qt.io/qt-5/qtwebengine-index.html">Qt WebEngine</ulink> to render websites.
+ Qt WebEngine is based on the <ulink url="https://www.chromium.org/blink/">Chromium Blink</ulink> source code.
+ Because Privacy Browser is built on the <ulink url="https://api.kde.org/frameworks/index.html">KDE Framework</ulink>,
+ it currently uses the <ulink url="https://community.kde.org/Schedules/Plasma_6">Qt 5</ulink> packages.
+ </para>
+
+ <para>
+ The current Qt 5 packages are in long-term support mode.
+ Qt WebEngine 5.15.x is based on <ulink url="https://wiki.qt.io/QtWebEngine/ChromiumVersions">Chromium 87.0.4280.144</ulink> from a feature perspective.
+ Security fixes are backported with <ulink url="https://wiki.qt.io/Qt_5.15_Release#Release_Plan">each release</ulink> every couple of months.
+ </para>
+ </sect1>
+
+ <!-- Bugs and missing features. -->
+ <sect1 id="bugs-and-missing-features">
+ <title>Bugs and Missing Features</title>
+
+ <para>
+ There is a list of feature requests and known bugs at <ulink url="https://redmine.stoutner.com/projects/privacy-browser-pc/issues">redmine.stoutner.com</ulink>.
+ Users should anticipate that all the current features of <ulink url="https://www.stoutner.com/privacy-browser-android/">Privacy Browser Android</ulink>
+ will also be implemented in Privacy Browser PC.
+ There is no need at this point to create features requests for these as they will be added as I start working on each feature and have a better idea of how they will be implemented.
+ However, each feature that has already been implemented should be bug free.
+ If you discover a bug that is not already documented at <ulink url="https://redmine.stoutner.com/projects/privacy-browser-pc/issues">redmine.stoutner.com</ulink> please add it.
+ </para>
+
+ <para>
+ Below is a list of known prominent bugs or missing features in this alpha release.
+ </para>
+
+ <itemizedlist>
+ <listitem><para>The page zoom is <ulink url="https://redmine.stoutner.com/issues/799">momentarily reset</ulink> every time a new URL is loaded.</para></listitem>
+ <listitem><para>If domain settings change the user agent, loading of the new URL is interrupted and the
+ <ulink url="https://redmine.stoutner.com/issues/821">previous site is reloaded</ulink>.</para></listitem>
+ <listitem><para>Browser <ulink url="https://redmine.stoutner.com/issues/831">error messages are not displayed</ulink> unless JavaScript is enabled.</para></listitem>
+ <listitem><para>Bookmarks are <ulink url="https://redmine.stoutner.com/issues/968">not yet implemented</ulink>.</para></listitem>
+ <listitem><para>Blocklists are <ulink url="https://redmine.stoutner.com/issues/969">not yet implemented</ulink>.</para></listitem>
+ </itemizedlist>
+ </sect1>
</chapter>
<!-- Using Privacy Browser. -->
<title>Using &privacybrowser;</title>
<para>
- <screenshot>
- <screeninfo>Here's a screenshot of &privacybrowser;</screeninfo>
- <mediaobject>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="privacybrowser.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>Screenshot</phrase>
+ </textobject>
+ </mediaobject>
+ </para>
+
+ <!-- JavaScript. -->
+ <sect1 id="javascript">
+ <title>JavaScript</title>
+
+ <para>
+ JavaScript allows web pages to run scripts (programs) on your device. It allows web pages to function more like apps, but it also allows web pages to spy on you.
+ Most of the tracking on the internet does not work when JavaScript is disabled.
+ JavaScript can be toggled by clicking on the privacy shield, which is blue if JavaScript is disabled and red when it is enabled.
+ <inlinemediaobject>
<imageobject>
- <imagedata fileref="screenshot.png" format="PNG"/>
+ <imagedata fileref="javascript.png" format="PNG"/>
</imageobject>
<textobject>
- <phrase>Screenshot</phrase>
+ <phrase>JavaScript</phrase>
</textobject>
- </mediaobject>
- </screenshot>
- </para>
+ </inlinemediaobject>
+ </para>
+ </sect1>
- <sect1 id="kapp-features">
- <title>More &privacybrowser; features</title>
+ <!-- Local Storage. -->
+ <sect1 id="local-storage">
+ <title>Local Storage</title>
<para>
- It slices! It dices! and it comes with a free toaster!
+ <ulink url="https://doc.qt.io/qt-5/qwebenginecookiestore.html#setCookieFilter">Local storage</ulink>
+ in Privacy Browser encompasses cookies, DOM storage, IndexedDB, service workers, and the filesystem API.
+ Local storage can be toggled through an action on the toolbar.
</para>
+ <!-- Cookies. -->
+ <sect2 id="cookies">
+ <title>Cookies</title>
+
+ <para>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="cookies.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>Cookies</phrase>
+ </textobject>
+ </mediaobject>
+ </para>
+
+ <para>
+ <ulink url="https://en.wikipedia.org/wiki/HTTP_cookie">Cookies</ulink>
+ allow websites to store small pieces of information for a specific host that are sent in the HTTP header every time the browser connects to that host.
+ Privacy Browser allows a maximum of <ulink url="http://browsercookielimits.iain.guru/">180 cookies with a maximum size of 4096 bytes per cookie</ulink> to be set per domain.
+ Cookies are often used to track users across the web, particularly third-party cookies (which are completely blocked in Privacy Browser).
+ They are also used as a security mechanism on websites where you log in to identify it is you as you browse from page to page on a site.
+ </para>
+
+ <para>
+ Durable cookies are shared with all tabs that are opened after they are made durable and are preserved even when Privacy Browser is restarted.
+ This allows users to stay logged in to sites of their choosing. No cookies are durable by default. Making a cookie durable requires specific user interaction.
+ </para>
+
+ <para>
+ All other cookies are specific to the tab where they are created and are destroyed when the tab is closed.
+ </para>
+ </sect2>
+
+ <!-- DOM storage. -->
+ <sect2 id="dom-storage">
+ <title>DOM storage</title>
+
+ <para>
+ <ulink url="https://en.wikipedia.org/wiki/Web_storage">DOM (Document Object Model) storage</ulink>, also knows as web storage, allows web pages to store information on a client device.
+ The storage capacity is larger than for cookies and the data is not automatically sent in the headers with every HTTP request.
+ In Privacy Browser, each website is allowed to store a <ulink url="https://arty.name/localstorage.html">5 MB of data</ulink> in DOM storage.
+ DOM storage requires JavaScript to function, and, in addition, requires an extra toggle to be enabled.
+ In Privacy Browser, DOM storage is limited to the tab where it is created and is destroyed when the tab is closed.
+ </para>
+ </sect2>
+
+ <!-- IndexedDB. -->
+ <sect2 id="indexeddb">
+ <title>IndexedDB</title>
+
+ <para>
+ <ulink url="https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API">IndexedDB</ulink>
+ provides web pages with a local database where they can store “significant amounts of structured data”.
+ There is disagreement on the internet about the maximum size of an IndexedDB database, probably because the various rendering engines keep changing their mind.
+ But it is usually listed at somewhere between 20% and 80% of <emphasis>your entire hard drive</emphasis> with each individual domain limited to some segment of that.
+ IndexedDB requires JavaScript to function.
+ In Privacy Browser, this database is limited to the tab where it is created and is destroyed when the tab is closed.
+ </para>
+ </sect2>
+
+ <!-- Service Workers. -->
+ <sect2 id="service-workers">
+ <title>Service Workers</title>
+
+ <para>
+ <ulink url="https://developer.chrome.com/docs/workbox/service-worker-overview/">Service workers</ulink> are offline JavaScript proxies of a website. They have their own cache that is usually hidden and hard to clear.
+ They were designed by people who want the web browser to become the operating system and run full “apps”.
+ In Privacy Browser, service workers are limited to the tab where they are created and are destroyed when the tab is closed.
+ </para>
+ </sect2>
+
+ <!-- Filesystem API. -->
+ <sect2 id="filesystem-api">
+ <title>Filesystem API</title>
+
+ <para>
+ The <ulink url="https://developer.chrome.com/articles/file-system-access/">filesystem API</ulink> grants the browser direct access to the files on your system.
+ Like service workers, the filesystem API is a summarily bad idea thought up by those who want the browser to become an operating system.
+ Even when JavaScript and local storage are enabled, the filesystem API does not work in Privacy Browser.
+ </para>
+ </sect2>
+ </sect1>
+
+ <!-- User Agent. -->
+ <sect1 id="user-agent">
+ <title>User Agent</title>
+
<para>
- The Squiggle Tool <guiicon><inlinemediaobject>
- <imageobject>
- <imagedata fileref="squiggle.png" format="PNG"/>
- </imageobject>
- <textobject>
- <phrase>Squiggle</phrase>
- </textobject>
- </inlinemediaobject></guiicon> is used to draw squiggly lines all over the &privacybrowser; main window. It's not a bug, it's a feature!
+ The user agent is a text string that is sent as part of every HTTP header that identifies the browser to the web server.
+ Privacy Browser's default user agent is <code>PrivacyBrowser/1.0</code>.
+ Qt WebEngine 5.15.12’s default user agent is <code>Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) QtWebEngine/5.15.12 Chrome/87.0.4280.144 Safari/537.36</code>.
+ </para>
+
+ <para>
+ Over the years user agents have become quite lengthy,
+ partially because they tend to include a <ulink url="https://webaim.org/blog/user-agent-string-history/">brief history of the internet</ulink>.
+ In the modern world they serve almost no good purpose, but some web developers still think they need them so they can send different version of their website to different browsers.
+ Some servers <ulink url="https://www.stoutner.com/user-agent-problems/">refuse to function correctly</ulink> if they don't like the user agent that is sent.
+ </para>
+
+ <para>
+ At some point in the future Privacy Browser will send no user agent by default.
+ Not only is that currently impossible because the Qt WebEngine doesn't allow you to not send a user agent (I will probably have to fork it to enable that functionality),
+ but even web servers that don't care what the user agent is often refuse to send an answer if there is no user agent at all.
+ Getting rid of this relic of the internet is going to take some time and a retraining of common expectations.
+ </para>
+ </sect1>
+
+ <!-- Domain Settings. -->
+ <sect1 id="domain-settings">
+ <title>Domain Settings</title>
+
+ <para>
+ Domain setting make it easy to automatically change JavaScript, local storage, user agent, and other settings when the domain changes.
+ Domain settings for the current domain can be accessed through the domain settings button at the far right of the URL line edit.
+ Domain settings for all domains can be accessed through the settings menu. When domain settings are active, the URL line edit will have a green background.
</para>
</sect1>
</chapter>
<chapter id="commands">
<title>Command Reference</title>
- <sect1 id="kapp-mainwindow">
+ <!-- Main Window. -->
+ <sect1 id="main-window">
<title>The main &privacybrowser; window</title>
+ <!-- File Menu. -->
<sect2>
<title>The File Menu</title>
<para>
<variablelist>
- <varlistentry id="file-new">
- <!-- Tip: With id's here, then you can use them like
- "select <xref linkend="file-new"/> to open the file dialog"
- which will be expanded to:
- "select File->New (Ctrl+N) to open the file dialog"
- -->
+ <!-- File > New Tab. -->
+ <varlistentry id="file-new-tab">
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">&Ctrl;<keycap>T</keycap></keycombo>
+ </shortcut>
+ <guimenu>File</guimenu>
+ <guimenuitem>New Tab</guimenuitem>
+ </menuchoice>
+ </term>
+
+ <listitem>
+ <para>
+ <action>Create a new tab.</action>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <!-- File > New Window. -->
+ <varlistentry id="file-new-window">
<term>
<menuchoice>
<shortcut>
<keycombo action="simul">&Ctrl;<keycap>N</keycap></keycombo>
</shortcut>
<guimenu>File</guimenu>
- <guimenuitem>New</guimenuitem>
+ <guimenuitem>New Window</guimenuitem>
</menuchoice>
</term>
<listitem>
<para>
- <action>Creates a new document</action>
+ <action>Create a new window.</action>
</para>
</listitem>
</varlistentry>
KActionCollection *actionCollectionPointer = this->actionCollection();
// Add the standard actions.
- KStandardAction::openNew(this, SLOT(fileNew()), actionCollectionPointer);
KStandardAction::print(tabWidgetPointer, SLOT(print()), actionCollectionPointer);
KStandardAction::printPreview(tabWidgetPointer, SLOT(printPreview()), actionCollectionPointer);
KStandardAction::quit(qApp, SLOT(closeAllWindows()), actionCollectionPointer);
findPreviousActionPointer = KStandardAction::findPrev(this, SLOT(findPrevious()), actionCollectionPointer);
// Add the custom actions.
+ QAction *newTabActionPointer = actionCollectionPointer->addAction(QLatin1String("new_tab"));
+ QAction *newWindowActionPointer = actionCollectionPointer->addAction(QLatin1String("new_window"));
userAgentPrivacyBrowserActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_privacy_browser"));
userAgentWebEngineDefaultActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_webengine_default"));
userAgentFirefoxLinuxActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_firefox_linux"));
UserAgentHelper *userAgentHelperPointer = new UserAgentHelper();
// Set the action text.
+ newTabActionPointer->setText(i18nc("New tab action", "New Tab"));
+ newWindowActionPointer->setText(i18nc("New window action", "New Window"));
userAgentPrivacyBrowserActionPointer->setText(userAgentHelperPointer->PRIVACY_BROWSER_TRANSLATED);
userAgentWebEngineDefaultActionPointer->setText(userAgentHelperPointer->WEB_ENGINE_DEFAULT_TRANSLATED);
userAgentFirefoxLinuxActionPointer->setText(userAgentHelperPointer->FIREFOX_LINUX_TRANSLATED);
hideFindTextActionPointer->setText(i18nc("Hide Find Text action", "Hide Find Text"));
// Set the action icons.
+ newTabActionPointer->setIcon(QIcon::fromTheme(QLatin1String("tab-new")));
+ newWindowActionPointer->setIcon(QIcon::fromTheme(QLatin1String("window-new")));
userAgentPrivacyBrowserActionPointer->setIcon(QIcon(":/icons/privacy-mode"));
userAgentWebEngineDefaultActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties")));
userAgentFirefoxLinuxActionPointer->setIcon(QIcon::fromTheme(QLatin1String("firefox-esr")));
findCaseSensitiveActionPointer->setIcon(QIcon::fromTheme(QLatin1String("format-text-lowercase")));
hideFindTextActionPointer->setIcon(QIcon::fromTheme(QLatin1String("window-close-symbolic")));
+ // Create the key sequences.
+ QKeySequence ctrlTKeySequence = QKeySequence(i18nc("The open new tab key sequence.", "Ctrl+T"));
+ QKeySequence ctrlNKeySequence = QKeySequence(i18nc("The open new window key sequence.", "Ctrl+N"));
+
+ // Set the action key sequences.
+ newTabActionPointer->setShortcut(ctrlTKeySequence);
+ newWindowActionPointer->setShortcut(ctrlNKeySequence);
+
+ // Execute the actions.
+ connect(newTabActionPointer, SIGNAL(triggered()), tabWidgetPointer, SLOT(addTab()));
+ connect(newWindowActionPointer, SIGNAL(triggered()), this, SLOT(newWindow()));
+ connect(zoomFactorActionPointer, SIGNAL(triggered()), this, SLOT(getZoomFactorFromUser()));
+ connect(cookiesActionPointer, SIGNAL(triggered()), this, SLOT(showCookiesDialog()));
+ connect(domainSettingsActionPointer, SIGNAL(triggered()), this, SLOT(showDomainSettingsDialog()));
+
// Update the on-the-fly menus.
connect(tabWidgetPointer, SIGNAL(updateUserAgentActions(QString, bool)), this, SLOT(updateUserAgentActions(QString, bool)));
connect(tabWidgetPointer, SIGNAL(updateZoomFactorAction(double)), this, SLOT(updateZoomFactorAction(double)));
// Process cookie changes.
connect(tabWidgetPointer, SIGNAL(updateCookiesAction(int)), this, SLOT(updateCookiesAction(int)));
- // Display dialogs.
- connect(zoomFactorActionPointer, SIGNAL(triggered()), this, SLOT(getZoomFactorFromUser()));
- connect(cookiesActionPointer, SIGNAL(triggered()), this, SLOT(showCookiesDialog()));
- connect(domainSettingsActionPointer, SIGNAL(triggered()), this, SLOT(showDomainSettingsDialog()));
-
// Connect the URL toolbar actions.
connect(javaScriptActionPointer, SIGNAL(triggered()), this, SLOT(toggleJavaScript()));
connect(localStorageActionPointer, SIGNAL(triggered()), this, SLOT(toggleLocalStorage()));
connect(tabWidgetPointer, SIGNAL(fullScreenRequested(bool)), this, SLOT(fullScreenRequested(bool)));
// Create keyboard shortcuts.
- QShortcut *ctrlTShortcutPointer = new QShortcut(QKeySequence(i18nc("The open new tab shortcut.", "Ctrl+t")), this);
QShortcut *f11ShortcutPointer = new QShortcut(QKeySequence(i18nc("The toggle full screen shortcut.", "F11")), this);
QShortcut *escapeShortcutPointer = new QShortcut(QKeySequence::Cancel, this);
- // Connect the keyboard shortcuts to the actions.
- connect(ctrlTShortcutPointer, SIGNAL(activated()), tabWidgetPointer, SLOT(addTab()));
+ // Connect the keyboard shortcuts.
connect(f11ShortcutPointer, SIGNAL(activated()), fullScreenActionPointer, SLOT(trigger()));
connect(escapeShortcutPointer, SIGNAL(activated()), this, SLOT(escape()));
}
}
-void BrowserWindow::fileNew() const
-{
- // Display a new instance of Privacy Browser.
- (new BrowserWindow)->show();
-}
-
void BrowserWindow::findNext() const
{
// Get the find string.
tabWidgetPointer->loadUrlFromLineEdit(url);
}
+void BrowserWindow::newWindow() const
+{
+ // Display a new instance of Privacy Browser.
+ (new BrowserWindow)->show();
+}
+
void BrowserWindow::refresh() const
{
// Remove the focus from the URL line edit.