Okay, hypothetically, if somebody was looking for a name for a Free Software project that focuses on Web censorship circumvention, using multiple configurable non-standard in-browser delivery mechanisms, what would a good name be?

Asking for a friend.

Basically the whole day of hacking on the little decentralization project today. Good progress. This thing is becoming surprisingly usable.

I will announce the new name (it's going to either be SideWays or Samizdat, most probably) early next week, and full code will follow shortly.

Haven't had a project I was that excited about for a long while. I missed that feeling a lot!

Show thread

Well that went fast! Rename complete, code a bit cleaned, stuff tested.

I give you Saмiзdaт:

Example deployment:

Go on, test in modern Firefox, Chromium, or Chrome.

There are g-glitches every now and then, but basically once the ServiceWorker kicks in you should see a "YES" there on the example page. When you do, you should also notice the favicon appearing. That means IPFS is working; there is no favicon on that server!

Show thread

is moving forward nicely. We now have some basic explanation on the landing page, a nicer display of methods used to fetch content, and (just implemented, hot from the CI/CD pipeline!) info on which resources were fetched using which method.

Check it out:

Pretty sweet, if I may be so bold to say so!

This is still Proof-of-Concept quality, and so many things can be done so much better. But it works already, in a way.

So, yay!

Show thread

For those new to the thing:
1. if you want to test it, load it, and then reload it -- or even close the tab and open a new one to load it again; this way the ServiceWorker will kick in and stuff will start happening;
2. it will not work without JS (sorry...), and it will not work in incognito/private mode.

To those who had already looked at it: I would be super interested if your service worker kicked in! You might not get the full functionality until the service worker reloads.

Show thread

TFW you need to refactor your code to use a completely new (to you) technique of dealing with some particular problem, using technology you don't really feel that comfortable with...

...and 2h later stuff actually works:

I am very okay with this.

Also, can now chain multiple delivery plugins. Which means I should now be able to implement caching using Caching API.

Show thread

Moar news: cache plugin implemented, but content not automagically pushed to local cache yet. You can test by:
1. going to cdn.test.occrp.org/projects/sa , reloading so that ServiceWorker kicks in
2. in JS console, run: await SamizdatPlugins[0].push(listLocalResources())
3. once the flurry of activity ends, block cdn.test.occrp.org in /etc/hosts
4. reload. should load immediately, and most resources should be marked as fetched from cache.

Show thread

Clearing cache is as easy as:
await caches.delete('v1')

Once you do that, while cdn.test.occrp.org is still blocked, you can reload the page and you should see load content (slowly...) from gun+ipfs.

So! Now we have two plugins. 😈

Show thread

New in : implemented auto-caching of successful requests, and UIs for clearing the cache and publishing to Gun+IPFS. Check it out: cdn.test.occrp.org/projects/sa

I will need to make caching a bit less aggressive, and/or Gun a bit more patient in waiting for the *latest* version of a given resource IPFS address, but all in all, works pretty ok.

Show thread

Also, some more UI niceness would be good -- displaying progress of pushing to Gun+IPFS, and informing user that cache has been successfully cleared, that sort of thing.

Show thread

Had a great long conversation with @tomasino about . Got some solid architectural advice. 👌🏾

Made fetch() into a plugin; we can now serve stuff from cache before a regular HTTP(S) fetch() goes out.

Next steps include:
- code cleanups
- reimplementing how we store/access data about which URL was retrieved how
- implementing a retrieve-from-cache-but-keep-fetching-in-background strategy so that a blocked site "loads" immediately, but the user still gets the fresh version eventually.

Show thread

Also added some project status info and how to contact us on the landing page and in the README:

My ToDo list still includes moving the project to a public Gitlab instance (0xacab.org probably, since it hosts a bunch of related projects including @sutty).

I really need to do this soon, but it requires setting up the CI/CD pipeline in a new location (probably on my own server). And that's a bit of work.

Show thread

Oooof, some serious code cleanups and rewrites in this weekend: git.occrp.org/libre/samizdat/c

The tl;dr is:
- regular fetch() is now also a plugin, which opens a number of possibilities;
- any plugin that can locally cache requests and responses is now treated specially: the first such plugin is called after a successful content retrieval automagically;
- if content is retrieved from cache, Samizdat continues trying to get it from a "live" source (fetch(), Gun+IPFS) in the background.

Show thread

This last bit was suggested by @tomasino and turned out to be simpler to implement than expected. So, yay!

To make a v1.0.0 that feels fully functional, we need to also:
- rewrite the SamizdatInfo (keeping the information on which resource was fetched and how) thing;
- add some fancy-shmancy UI displayed on any Samizdat-managed page;
- which will together allow us to inform the user "hey, we got this from cache, but there seems to be fresher version; reload please".

Okay people, riddle me this: in I have a and one or more browser window contexts (aka "clients) that might be using said ServiceWorker. I would like to pass some information between the two. Most importantly I would like to inform the relevant browser window that all the fetches that the ServiceWorker was handling on its behalf are done.

Here's the ticket for more context

Show thread

Currently I am doing this by keeping the relevant information in Indexed DB. This has drawbacks:
- data is the same for all browser windows, leading to potential confusion if there is more than one tab open using the ServiceWorker
- there are no events to hook to catch when Indexed DB data changes, so it's down to setInterval() method, which is fugly.

Show thread

I *could* use Client API, specifically `postMessage` with `FetchEvent.clientId`, but clientId is not implemented on Safari (both Desktop and Mobile):

Show thread

I *could* use MessageChannel API, but it requires setting up a channel between browser window and the SW, and there's no way to track which channel is used for which browser window.

Plus, SW is quickly reaped, context destroyed, channel killed. On a new fetch() ServiceWorker restarts but the channel does not work, so a new channel would need to be set-up.

But that can only happen from the browser window side, whereas only the ServiceWorker knows a fetch() has started.

🐔 🥚

Show thread

I *still* could decide to use MessageChannel API, but would need to:
- keep track in SW which fetch is from which referrer (not sure that's possible even; probably available in Request.Headers)
- keep track which channel is for which URL/referrer
- it would still get confusing if there are two tabs open with the same URP
- and I would still need to do polling in setInterval() on browser window side, kinda defeating the purpose of the channel.

Show thread

So unless there is a way to hook an event in a browser window whenever a fetch() starts or when all fetch() events finish, MessageChannel API doesn't seem to be better than just using Indexed DB and polling it in setInterval() on a regularly.

And so it doesn't seem it makes sense to use MessageChannel API at all, since either it's not effective, or clientId gets implemented in Safari soon and we should move to that.

Show thread



Show thread


Show thread






Show thread


Merge request here:

Still work in progress though.

Show thread


Show thread

The Merge Request of Doom:

Try here:



Show thread



Show thread

Ok, back to playing with after some traveling.

- caching plugin not double-counted anymore;
- finally there is a proper project website at samizdat.is/


Main project home still git.occrp.org/libre/samizdat/ for the time being, but hoping to move it to a public GitLab instance soon.

Show thread

Ok, we have the and Gun daemons deployed on the new server for , and content for samizdat.is/ pushed to IPFS and Gun.



Show thread

Oh boy, the CI/CD pipeline at 0xacab.org did not work because I did not enable it in project settings. ! 🤦‍♀️

But ow it works! So we have the first successful deploy of samizdat.is/ from its new git home:


Show thread





Show thread
Show more

@tomasino thanks! I hope it's at least a tiny bit more readable now.

There's a bug where fetch plugin is called twice, but I know what's going on and I think I know how to fix it.

I'll try to work on feature branches from now on, so as not to screw you over in case you want to work on something. ;)

My next step might be the Samizdat UI.

@rysiek I tried in my Odysseus web browser, because also WebKit, and I'm just seeing messages in various places ammounting to "no service worker support".

It's probably similar in Safari, but I can't say for sure.

@alcinnz right. Well, requires service worker support, so if that's missing, then it's not going to work.

@rysiek "[Log] (c223b08c) Error while registering a service worker: (samizdat.js, line 71)
TypeError: SyntaxError: Unexpected token '='. Expected an opening '(' before a method's parameter list." Safari 13.0.3.

@rysiek safari mobile is a no. I’ll check desktop in a bit.

@rysiek looks great congratulations! (could use some css tweaks on iOS, its loads a bit too wide)

Show more
Sign in to participate in the conversation
