Skip to content

Content protection#194

Merged
JayPanoz merged 39 commits intodevelopfrom
protection
Feb 24, 2026
Merged

Content protection#194
JayPanoz merged 39 commits intodevelopfrom
protection

Conversation

@JayPanoz
Copy link
Copy Markdown
Contributor

This PR is meant to provide protection to contents e.g. dragging, copying, dev tools, right-click, selecting all, etc.

It is entirely customisable and is disabled by default. When possible, protection is improved through multiple layers.

This also introduces a new listener so that apps can react to events triggered by this new API, and provide additional layers if they deem necessary.

Still a draft cos it needs documentation and a thorough review.

@JayPanoz JayPanoz marked this pull request as ready for review February 17, 2026 14:28
@JayPanoz JayPanoz requested a review from chocolatkey February 17, 2026 14:28
Copy link
Copy Markdown
Member

@chocolatkey chocolatkey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your work on this! My questions/suggestions:

Printing

Why disable printing with hotkeys when the CSS solution is already implemented? Users can use their browser's menus to trigger the printing anyway without using their keyboard at all.

Devtools

Same question, but for a different reason - anyone sophisticated enough to attempt opening dev tools will just choose the menu option instead.
I would suggest, rather than trying to disable dev tools with hotkeys, methods explained here be implemented. Of course this doesn't prevent dev tools from opening, but you can take an action when this happens such as closing the reader.

Comment thread navigator-html-injectables/src/modules/snapper/ColumnSnapper.ts Outdated
Comment thread navigator/src/injection/webpubInjectables.ts
@JayPanoz
Copy link
Copy Markdown
Contributor Author

Why disable printing with hotkeys when the CSS solution is already implemented? Users can use their browser's menus to trigger the printing anyway without using their keyboard at all.

Swiss cheese theory pretty much. Hence the different layers you can enable/disable + listeners you can react to specifically.

That said it feels like keyboard combos should probably be a thing on their own with config and a dedicated listener, as we need it for Peripherals/keyboard handling in apps for more than content protection. Now it feels strange we have this customisation in here and I even used it to test other things not related to content protection myself in the last couple of days.

We could then probably reuse the built-ins through content protection with new config properties, and allow for customisation of the rest through a new “API” – I don’t really see how to handle this through listeners because we cannot access the iframe’s event at this level, we have to preventDefault() before sending the message. And we cannot prevent all keys/combos by default for obvious accessibility reasons.

I would suggest, rather than trying to disable dev tools with hotkeys, methods explained here be implemented. Of course this doesn't prevent dev tools from opening, but you can take an action when this happens such as closing the reader.

Yeah this is exactly the idea through the contentProtection listener, that you could even remove the Navigator from the DOM if you wanted to do so. I have been a little bit cautious because of false positives – see upcoming comment specific to scrollProtection. But will take a look and see what results it can bring. Thanks!

@danielweck
Copy link
Copy Markdown
Member

just out of interest, was prior art like https://github.com/d-i-t-a/R2D2BC/blob/develop/src/modules/protection/ContentProtectionModule.ts tested to evaluate the pros and cons of various different techniques ?

@JayPanoz
Copy link
Copy Markdown
Contributor Author

@danielweck yeah more or less, there aren't that many techniques known to work that well so you usually find the same ones in a lot of different places. And of course they are infamous projects a lot of people are using or were inspired by.

For transparency's sake, what I tried to focus on early, and that also explain the development of the Injection API, is providing ways for apps to design and implement additional layers around the built-ins since it presented three major benefits:

  1. Consumers of the package are no longer relying on us entirely, they can extend content protection as they deem necessary
  2. If we have to update/improve/correct something, they do not have to wait on us, they can implement temporary or transitional logic/heuristics
  3. This helps implement more nuanced approaches and heuristics, as you can then rely on several observations to act upon suspicious activity instead of risking ruining the User Experience because of false positives in one.

Obviously, one would expect this will not be a one-shot PR and we never come back to it, it will have regular updates in the next months – and even years –, new features, additional layers, bug fixes, etc. But at least this helps destress maintenance a little bit as consumers are not stuck because of and waiting on us.

What I often noticed during research is that it often felt like collections of features rather than a cohesive system that lets you extend protection, so I tried to build a system with reliable detection, weighing costs in terms of performance and UX, etc. – that is why some pattern analysis has been disabled for example.

@JayPanoz JayPanoz requested a review from chocolatkey February 18, 2026 17:37
So that you can handle bookmarks, annotations, etc.
@JayPanoz
Copy link
Copy Markdown
Contributor Author

@chocolatkey added dev tools detection with what made more sense to me from the doc you linked, especially considering our baseline, and it seems to behave nicely re. false positives. Rerequested a review so that you can chime in as I am not sure whether we need more from the start.

Note shortcuts have been migrated to a new keyboardPeripherals API of sorts, with their own listener, so that apps can pass combinations and a type – and then you can plug your callbacks into listeners. That should help with privatizing cframes, although we know we are missing a proper Decorator API that I will tackle with media overlays, after audiobooks.

Previous shortcuts are reserved in this new API and are enabled through Content Protection config. A common module in Injectables is used so that things cannot go out of sync in Navigators (parent window) and Injectables (iFrames).

Would be nice if you could take a look in the next couple of weeks as audiobooks, which is being Worked on in parallel, will eventually need to have content protection too. It is not urgent, and I can come back to it later as I will need to do a lot of implementation and debugging of audio nahigator anyway, and design a Timeline API.

Will also add an alternative option for testing locally using a file: pattern, due to pnpm link having some issues in some frameworks. It can be quite infuriating to deal with that if it happens so the more options we provide, the better.

Copy link
Copy Markdown
Member

@chocolatkey chocolatkey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A good start, I think we should merge and continue testing/improving this in thorium-web based on real-world data

@JayPanoz
Copy link
Copy Markdown
Contributor Author

JayPanoz commented Feb 24, 2026

Thanks!

Sounds good. The Thorium Web implementation should be crude-ish at first as I am not sure preferences can scale very well if we need to handle this on a route/category/publication basis but this is the option we have right now.

Note I will merge #195 as well so that we can group theses changes into a single new minor version. In practice ReadiumCSS stable is a patch so let's spare us the burden of releasing a patch version immediately after a new minor one.

@JayPanoz JayPanoz added this pull request to the merge queue Feb 24, 2026
Merged via the queue into develop with commit 96ec778 Feb 24, 2026
@JayPanoz JayPanoz deleted the protection branch February 24, 2026 11:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants