Hello, I am Yuchen, and I will be talking about
how Emacs may be used to save user freedom on the web.
I will begin by describing the background issues,
followed by solutions outside of Emacs.
Then I will move into the main business of describing
several ways to address the issues using Emacs,
including free clients in Emacs, web browsers,
also known as universal clients in Emacs,
approaches using Emacs web server and Emacs web framework,
which allows one to write an Emacs package
and get a web app for free,
as well as using Emacs as a Firefox extension.
OK, let's now move on to
the background issues for this topic.
Many of you probably already know what is free software.
It is software that respects four user freedoms,
including freedom 0, which is the freedom to use,
freedom 1 is the freedom to study and modify a program,
freedom 2 is the freedom to
distribute exact copies of a program,
and freedom 3 is the freedom to distribute modified copies.
Different environments have different norms
with regards to user freedom.
For example, GNU/Linux distributions
default to free software,
even though the official kernel Linux
contains non-free code, like non-free firmware.
What I mean is, people generally expect free software
in these environments.
There's plenty of free software
built on other free software,
so generally people can accomplish tasks
using free software only.
Emacs, by comparison, is even better.
It has freedom built-in, as it is highly customizable
with self-documenting configurations.
When a Lisp form is evaluated by the user in Emacs,
the change is instantly reflected in the environment.
Thus, it converts users to hackers effortlessly.
From writing setq statements,
which is similar to configurations
in the majority of other programs,
to writing functions,
which are building blocks of Elisp features,
to writing features and publishing packages,
it is a natural progression.
In this sense, Emacs perhaps has
the most gentle learning curve for hackers.
On the other hand, the default license
in the Emacs community
is GNU General Public License version 3 or later,
which is the best free software license
apart from the Affero license.
Now let's move on to web browsers,
which by contrast does not default to freedom.
For one thing, free software JavaScript projects
default to Expat license,
which is also commonly known as the MIT license,
which is a lax permissive license that could be exploited
as developers could write non-free derivatives
and subjugate user freedom.
This also contributes to the JavaScript trap.
Most popular web browsers nowadays simply download and run
any JavaScript code requested by the web page.
Generally speaking, there are two camps on this issue.
One side would say JavaScript is simply part of life,
and an integral part of the so-called modern web.
Just accept it, and there is no point in fighting it.
Indeed, it can be frustrating when greeted by
"This page requires JavaScript and cookies to continue,"
or even a blank page when opening a web page
while disabling JavaScript.
The other camp takes a more principled position
and says JavaScript is unnecessary.
I mean, people use the web mainly for
database-like operations
to interact with data stored on other people's computers,
like querying, creating, updating, deleting.
I mean, 99% of the things happen in getting data,
including reading news, watching videos,
downloading images, etc.,
and posting data, including publishing
this sort of materials, publishing news comments, videos.
Why does this need any programs
to do funny computations, right?
Modern web browsers are also a pain to use.
They are the opposite to Emacs
in terms of customization capabilities.
Such problems on the client side
is the main focus of this talk.
On the server side, the issue is known as SaaSS,
service as a software substitute.
It is about doing computing for users
on other people's computers,
which the user has no visibility, let alone control.
Examples include translation or photo editing
in so-called web applications.
Another example would be web applications
make recommendations based on user data
and suggest what the users read or watch next.
On the one hand, SaaSS is an intractable problem
because free software is all about user freedom
on one's own computer,
not someone else's computer.
On the other hand, this is also a lesser problem
because it has trivial solutions,
which is self-hosting and keeping computations local.
Wouldn't it be nice to use a photo editing web application,
but without the web?
Right, now let's move on to solutions outside of Emacs
that tackle these problems.
There are generally two ways to fix this issue.
One is blocking non-free JavaScript,
and the other is substituting with free programs.
Let's start with blocking.
LibreJS, for example, is a Firefox extension
blocking non-free, non-trivial JavaScript.
It works by intercepting, filtering
all requests for JavaScript,
recognizing the ones that are trivial or free,
and blocking the execution of the others.
As an experiment, I logged the LibreJS output
for about two weeks,
and during which, of all the web pages I loaded,
23 domains have at least some LibreJS-compliant scripts.
That is not much, though I did use other means
to reduce the scenarios
where I need to load web pages with JavaScript in Firefox,
like using a text browser like Lynx.
Then there's also NoScript, which is like LibreJS,
but it blocks all scripts, whether free or non-free, trivial or non-trivial.
So the problem with blocking is that
blocking with certain scripts and accepting others,
there are like... I can think of two problems.
One is that it does not help with Freedom 1,
which is the freedom to allow users to modify a program
and use it in place of the original program.
And also it does not help
when the non-free JavaScript is mandatory
for the functioning of the web page.
For example, some pages are blank
when non-free JavaScript is not executed.
So now let's move on to the substitution, the other method.
Let's start with userscript.
It is a script, it is a user-specified JavaScript
injected to a web page.
A typical example of userscript tool is GreaseMonkey.
Another idea is a proxy that replaces scripts in place,
that is, sending user-specified scripts
as a response to requests for such scripts.
So one example would be Haketilo, however you pronounce it.
It's a tool that's built on top of mitmproxy.
It is supposed to do this.
I haven't used GreaseMonkey nor Haketilo
for these purposes yet,
so I can't say much about these options.
So then there are also free clients
which replace the whole frontend,
instead of a script requested by web pages
from the official web clients.
People often refer to them as alternative frontend.
YouTube is perhaps the best example
as there are so many free clients,
including Invidious for the web,
youtube-dl and yt-dlp on the command line,
MPV and VLC as GUI desktop, LibreTube
and NewPipe for Android and so on.
Youtube-dl and yt-dlp are especially versatile
as they work with many video and audio sites
with extractors written in Python,
so people can add extractors like extensions.
A similar tool would be woob,
short for web outside of the browsers.
It is a command-line and GUI program
that interacts with many web services, even banks.
And there are browser extensions
that automatically redirect to these clients.
For example, Redirector and Libredirect
redirect to the free web clients.
One could use OpenWith, another extension,
to redirect to free non-web clients,
for example by opening YouTube links with MPV.
Now let us move to Emacs-based solutions.
They are based on the same ideas but using Emacs.
First, free clients in Emacs.
Basically alternative frontends written in Elisp.
There are several advantages.
For example, integration with other Emacs tools,
good for archiving, making use of Emacs libraries,
extensibility, thanks to Emacs' own
extensibility and customizability.
Examples include mastodon.el for mastodon,
or mastorg for viewing and archiving toots with org,
sx for Stack Exchange, buildbot.el for buildbot, etc.
Here's an example of mastorg displaying
the hierarchy of a toot in org.
Just wait. Right.
So this is the toot itself, this is a first reply,
this is a reply to the reply, and so on.
And here is an example of
opening a Stack Exchange link using sx.
Let's check out the tag.
So we can browse the Stack Exchange Emacs site with ease.
The idea is quite simple.
Just use APIs to get data and display it in Emacs,
or just to scrape, like requesting HTML and processing it.
An example of scraping is hnreader,
which scrapes Hacker News web pages
and renders them in Org buffers.
Here's how hnreader fetches
and displays the Hacker News front page.
And one could go into the comments,
which shows a similar hierarchy to mastorg's output.
And of course, there are limitations for this method,
which is not limited to Emacs.
There are basically limitations
to any ad hoc bespoke clients,
which is catch-up games with remote server,
which may change the API interface endpoints
or even structure of the responses.
This brings us to web browsers in Emacs.
Web browsers are universal clients
because all sites support browsers.
So in a world of no JavaScript,
there will be no need to write bespoke clients.
In such a world,
instead of using JavaScript code to fetch JSON,
web developers make server do the heavy lifting
and just send the complete HTML over.
Okay, back to reality.
EWW, the default Emacs browser,
is what people refer to as a text browser,
even though it is not text only and it supports images too.
It is a good solid browser that supports forms, etc.
The downside is that it does not support CSS,
so the formatting could be a bit ugly sometimes.
There are some other browsers in Emacs too,
like emacs-w3m, which is backed by w3m,
and Luwak, which is backed by Lynx.
Sorry for the naming, by the way.
They often consist of a backend
that fetches URL and parses HTML.
For example, the built-in URL package
and the libxml2 binding in Emacs are decent enough.
And the frontend that renders the HTML,
like shr or lynx, etc.
There is also an xwidget-webkit,
but this browser executes JavaScript,
so it does not really help in this case.
Browser extensions on Emacs are effortless,
as they can be written as Emacs packages.
For example, one could easily write
Elisp scripts with similar functionalities
to libredirect and openwith
to redirect links, to rewrite URLs,
or to open, say, a YouTube URL with MPV,
but with even more flexibility.
For example, here's how one could
transform a Zoom link to a dial-in number
so that it is easier to join a Zoom meeting
without running non-free JavaScript.
This might still be bad for privacy,
but at least it's good for freedom.
As mentioned before,
one shortcoming of these Emacs-based browsers,
Emacs web browsers, is no support for CSS,
so the formatting could leave a lot to be desired.
Maybe someone would write
an Emacs browser package backed by wkhtmltopdf,
which, when opening a URL,
it calls wkhtmltopdf to convert the web page to PDF
and opens in, say, pdf-view-mode of the pdf-tools,
thus containing formatting,
and all the URL clicks resolve to the same actions.
Also, wkhtmltopdf contains a flag that disables JavaScript.
Another idea would be to use Firefox
as a processor to fetch URLs.
Maybe it can be used to pass back the HTML
after executing free JavaScript,
say, if Firefox has LibreJS installed.
This requires Firefox to send back the DOM,
which could be achieved using native messaging.
More on that later.
Alternatively, one could also write a Firefox extension
that sends the DOM in an existing tab back to Emacs.
But thinking more about it,
I don't think this is actually a useful idea,
because most of the sites that work under LibreJS
also are useful when all JavaScript is blocked.
So, this means these sites are viewable
under EWW, Luwak, etc.
And another issue is that
this could also make running non-free JavaScript easier,
which is harmful to user freedom.
OK, let's move on to the idea
of running Emacs as a web server,
so that Emacs client packages are web apps
serving as alternative frontends.
Why would we want to do this?
Well, as much as one wants to be always in Emacs,
it is not always feasible.
For example, one may be on the go
and needs to look up something on the phone.
On the other hand, Emacs client packages
are just alternative frontends
but written in Elisp and run in Emacs.
With the help of emacs-web-server package,
we can access Emacs packages on the web.
emacs-web-server package is not something new,
but seems to be underused in the community somehow.
OK, let's start with a simple example called hello-emacs.
It is pretty straightforward.
Just require the web server feature
and run ws-start to start a server process
and send the string "hello emacs"
to the process regardless of the request.
As you can see, it is going to be available
at port 9000 of localhost.
Let's try it out.
We need to first evaluate this code block.
And it works.
To stop a server, just run ws-stop on the web server object.
Let's evaluate.
Yep, it stopped.
OK, now let's move on to something funny
that you should never run on the public web.
I call it yolo.el.
It uses htmlize
to make any Emacs buffer available on the web.
Let's try it out.
Just require the thing and start the server by yolo-start.
And it's available at port 9999.
By default, the root domain shows the splash screen
which needs to be available.
Running display-splash-screen ensures that,
but here I've already run it.
So let's have a look.
And here we have the splash screen.
Emacs tutorial and such.
Unfortunately, none of these links work,
which is something we will revisit later.
So, to show an arbitrary buffer,
just use the buffer name as a path.
For example, the slide has the buffer named web.org,
so we can display it.
Let's try something fancier,
like the man page of ffmpeg.
So this is the man page of ffmpeg.
And the buffer name is a bit more complicated.
I have the URL available here.
It's missing a star.
It's pretty neat if you ask me.
And, yeah, what else?
Well, we can also browse EWW in Firefox.
For example, let's check out gnu.org,
and note that the buffer name is EWW with stars.
So, ah, it works.
And it has all the graphics even.
Now, how about we do it the other way around?
So we load the current slide web.org using this funny thing.
And it works.
Not as nice as the Org buffer, though.
Right, and now that gives me some funny idea.
So I'm a firm believer that memes are meant to be enjoyed
in silence rather than read out loud.
So I will jump straight to trying this idea,
which is loading the EWW buffer URL with EWW itself.
Loading, loading, loading.
Spoiler alert, it never loads.
So that concludes the demo.
And so we can stop the server, web server, with `yolo-stop`.
So one could extend yolo to serve arbitrary Emacs commands,
making it even more dangerous.
That is, for example, `localhost:9000/m-x/magit-status`
would run `magit-status`
and show the magit-status buffer in the web browser.
Or localhost:9000/m-x/eww/
any arbitrary URL to browse arbitrary URL
with EWW inside of Firefox.
It can serve as a way to block all JavaScript,
because EWW does not support JavaScript.
And enforce preferred colorscheme in Firefox,
since htmlize, as you have noticed,
faithfully reflects the theme used in Emacs.
Okay, so we know that yolo is unsafe
and needs to be refined.
In fact, we don't necessarily want
to run Emacs on a web browser.
After all, a modern web browser is
something one has to fight all the time
and should be avoided whenever possible.
We want to instead be able to access things
when forced to be in a web browser,
in which case only the motivations
of an alternative frontend apply.
Moreover, the ideal situation is an Emacs web framework,
a tool that automatically
transforms Emacs packages to web apps,
so that one does not need to write extra code
to get a web app that does the same thing as the package.
We also need all links in the web pages to work.
As noted before, the links on the yolo Emacs splash screen
do not work.
So here's a proof-of-concept example. It's called bom.el.
It gets some weather forecast data
from the Australian Bureau of Meteorology
and displays it in an org buffer.
So let's try it out. One could do `M-x bom`,
which shows an org buffer with links to each state.
So based in Melbourne, naturally,
I would like to find out the weather of Victoria.
And yes, to execute this command. Wait, wait, wait. Right.
And we are at a buffer that shows
the weather forecast of the whole of Victoria
in the hierarchy. Note that this back button
takes you to the previous page.
So here are the regions of Victoria.
I think Melbourne is in Central.
And yeah, it shows
the seven-day weather forecast of Melbourne.
You can also reach this page by running,
let's see, directly `M-x bom-state`.
Vic.
OK. So this works.
And this is bom as an Emacs package.
Now let's check out bom as a web app
transformed by Emacs web framework.
So start the web server with bom-start.
And let's try it out. It's at 9000 again.
Oops. Invalid path. Oh, that's because
it makes exactly one command to one path.
So remember that we used the bom command
to show the landing page.
So here we need the bom in the path as well.
And it shows the same landing page, except in HTML.
Let's check out Victoria weather forecast as before.
And it shows an HTML converted from the org buffer
using ox export HTML, whatever.
And you can see even the back button is here.
That takes you to /bom.
So let's have a look at Melbourne. Here it is.
Hooray, it works.
So, yeah, as usual,
you can stop the web server with `M-x bom-stop`.
Right. And alternatively,
it can also be deployed directly in terminal
in a dedicated Emacs daemon.
So you can see that there's a one-one correspondence
between the Emacs package interface and the web interface.
And that implies some restrictions to the Emacs package
for the Emacs web framework to be able to do its job. Right.
For example, the package needs to have an Org interface
and the links that trigger other commands
need to be in Elisp links
so that the Emacs web framework
can translate it to web server URL path.
Note that Emacs web server framework is not a real package.
I wrote some functions in bom.el serving the purpose,
and they should be separated out eventually
without much trouble.
One could get weather forecast
without running JavaScript anyway,
which makes bom.el less important
as an alternative web client.
Though it does provide, dare I say,
a clean and minimal interface
compared to common weather forecast web pages.
Other more relevant use cases could be Mastodon,
whose official web client requires JavaScript
to display a post.
The mastorg package that shows an Org hierarchy of toots
rooted as a given toot could be a low-hanging fruit.
The limitation of Org interface requirements
can also be relaxed in further work,
if one could extend Emacs web framework
to translate back and forth between Emacs widgets,
say, including buttons and web page widgets,
including links.
Another more far-fetched idea would be
to translate to other types of interfaces,
like GNU/Linux or Android GUI.
How about animations? Say, M-x butterfly,
or even web games from Emacs games?
Possibilities are unlimited in this, as always, in Emacs.
I also noticed some limitations
when trying to actually host bom.el on the public web.
Given the limited access to the Emacs server,
I was comfortable enough to give bom.el a go
to serve it on the public web.
However, I immediately stopped
after noticing how slow it is.
It can take more than 30 seconds
to load a page of weather forecast for a state.
I am also not sure how many simultaneous connections
it can handle.
In any case, I think the package emacs-web-server
could do with some performance enhancement.
Right. Because of the time constraints,
I will briefly touch one final idea,
which is to use Emacs as a Firefox browser extension.
We already have org-protocol,
which allows Firefox to communicate
with a running Emacs server
by sending an org-protocol URL to the latter.
It can be used not just for capturing or storing links,
but to execute arbitrary code on any component of the URL.
However, it is fire and forget,
and Emacs cannot tell Firefox what to do.
There may be a length restriction, too.
For example, Firefox may not be able to send back
the whole DOM.
This claim needs to be verified, though.
Native messaging is one solution to this problem.
It is a two-way communication channel
between a Firefox web extension and a local system process
started by the web extension.
The process could be an Emacs server,
which would make Emacs effectively
a Firefox web browser extension.
In this case, Elisp would be the main extension language,
rather than JavaScript.
However, JavaScript is still needed at the Firefox end
of the communication channel.
As a simple example of this idea,
Firefox could ask Emacs to redirect a URL
by removing tracking and using alternative frontend, etc.
However, I was not able to implement this
due to some tricky business
with enforcing synchronicity
that allows the web extension
to wait for responses from Emacs.
Some further work, I suppose.
That concludes my talk.
Thank you for your attention.