Skip to content

Commit 1209590

Browse files
committed
Add BETA encrypted_something
1 parent 4143a49 commit 1209590

File tree

3 files changed

+130
-82
lines changed

3 files changed

+130
-82
lines changed

README.md

Lines changed: 60 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -188,47 +188,87 @@ plugins:
188188
password_button_text: 'custome_text_button'
189189
```
190190
191-
### Encrypt Table Of Content
191+
### [:wrench: BETA] Encrypt Something
192192
193193
Related to [issue #9](https://github.com/CoinK0in/mkdocs-encryptcontent-plugin/issues/9)
194194
195-
You can add `encrypted_toc: True` in plugin config variable, to encrypt the table of contents.
195+
You **have to** enable [feature tag encrypt page](https://github.com/CoinK0in/mkdocs-encryptcontent-plugin#tag-encrypted-page) for this feature to work properly.
196196
197-
You **have to** enable [feature tag encrypt page](https://github.com/CoinK0in/mkdocs-encryptcontent-plugin#tag-encrypted-page)
198-
for this feature to work properly, cause HTML generation of the Table Of Content is done after the rendering process.
197+
Add `encrypted_something: {}` in the plugin configuration variable, to encrypt something else.
199198

200-
When this feature is enabled, we search for your table of content based on `id=mkdocs-encrypted-toc` and encrypt all HTML content.
199+
The syntax of this new variable **MUST** follow the yaml format of a dictionary.
200+
Child elements of `encrypted_something` are build with a key `<unique name>` in string format and a list as value.
201+
The list have to be contructed with the name of an HTML element `<html tag>` as first item and `id` or `class` as the second item.
201202

202203
```yaml
203-
plugins:
204-
- encryptcontent:
205-
tag_encrypted_page: True
206-
encrypted_toc: True`
204+
encrypted_something:
205+
<uniq name>: [<html tag>, <'class' or 'id'>]
207206
```
208207

209-
Adding `id=mkdocs-encrypted-toc` in the parent element of your table of content, so that the child html contained to be encrypted.
210-
It possible to use conditional tag `page.encrypted` to add or not the id.
208+
The `<unique name>` key identifies the name of a specific element of the page that will be searched by beautifulSoup.
209+
The first value of the `<html tag>` list identifies the type of HTML tag in which the name is present.
210+
The second value of the list, as string `'id'` or `'class'`, specifies the type of the attribute which contains the unique name in the html tag.
211+
212+
Prefer to use an `'id'`, however depending on the template of your theme, it is not always possible to use the id.
213+
So we can use the class attribute to define your unique name inside html tag.
214+
BeautifulSoup will encrypt all HTML elements discovered with the class.
215+
216+
When the feature is enabled, you can use any methods *(password, button, cookie)* to decrypt every elements encrypted on the page.
217+
218+
By default **every child items** are encrypted and the encrypted elements have `style=display:none` to hide their content.
219+
220+
#### How to use it :exploding_head: ?! Examples
221+
222+
Use the `page.encrypted` conditions to add attributes of type id or class in the HTML templates of your theme.
223+
Each attribute is identified with a unique name and is contained in an html element.
224+
Then add these elements in the format of a yaml dictionary under the variable `encrypted_something`.
225+
226+
1. For example, encrypt ToC in a theme where ToC is under 'div' element like this :
211227

212228
```jinja
213-
{%- if page.toc|count > 0 %}
214229
<div class=".." {% if page.encrypted %}id="mkdocs-encrypted-toc"{% endif %}>
215230
<ul class="..">
216-
{%- for toc_item in page.toc %}
217231
<li class=".."><a href="{{ toc_item.url }}">{{ toc_item.title }}</a></li>
218-
{%- for toc_item in toc_item.children %}
219-
<li><a href="{{ toc_item.url }}">{{ toc_item.title }}</a></li>
220-
{%- endfor %}
221-
{%- endfor %}
232+
<li><a href="{{ toc_item.url }}">{{ toc_item.title }}</a></li>
222233
</ul>
223234
</div>
224-
{%- endif %}
225235
```
226236

227-
When the feature is enabled and you use any methods *(password, button, cookie)* to decrypt the page, the table of contents will also be decrypted.
237+
Set your configuration like this :
228238

229-
By default the encrypted ToC have `style=display:none` to hide encrypted content.
239+
```yaml
240+
encrypted_something:
241+
mkdocs-encrypted-toc: [div, id]
242+
```
243+
244+
2. Other example, with multiples target. In you Material Theme, you want to encrypt ToC content and Footer.
245+
246+
Materiel generate 2 `<nav>` structure with the same template `toc.html`, so you need to use a `class` instead of an id for this part.
247+
The footer part, is generated by the `footer.html` template in a classic div so an `id` is sufficient
248+
249+
After modification, your template looks like this :
250+
```jinja (toc.html)
251+
<nav class="md-nav md-nav--secondary {% if page.encrypted %}mkdocs-encrypted-toc{% endif %}" aria-label="{{ lang.t('toc.title') }}">
252+
<label class="md-nav__title" for="__toc"> ... </label>
253+
<ul class="md-nav__list" data-md-scrollfix> ... </ul>
254+
</nav>
255+
```
256+
```jinja (footer.html)
257+
<footer class="md-footer">
258+
<div class="md-footer-nav" {% if page.encrypted %}id="mkdocs-encrypted-footer"{% endif %}> ... </div>
259+
<div class="md-footer-meta md-typeset" {% if page.encrypted %}id="mkdocs-encrypted-footer-meta"{% endif %}>
260+
</footer>
261+
```
230262

263+
Your configuration like this :
264+
```yaml
265+
encrypted_something:
266+
mkdocs-encrypted-toc: [nav, class]
267+
mkdocs-encrypted-footer: [div, id]
268+
mkdocs-encrypted-footer-meta: [div, id]
269+
```
231270

271+
:gear: This feature is still in beta, all feedback, improvement, fixes, are welcome.
232272
## Contributing
233273

234274
From reporting a bug to submitting a pull request: every contribution is appreciated and welcome.

encryptcontent/decrypt-form.tpl.html

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -85,33 +85,39 @@ <h1>{{ summary }}</h1>
8585
{% if password_button %}
8686
decrypt_button = document.getElementById("mkdocs-decrypt-button"),
8787
{% endif %}
88-
{% if encrypted_toc %}
89-
//encrypted_toc = document.getElementById('mkdocs-encrypted-toc'),
90-
// HTMLCollection, cause we can have multiples ToC items ...
91-
encrypted_toc = document.getElementsByClassName('mkdocs-encrypted-toc'),
92-
{% endif %}
9388
decrypt_form = document.getElementById('mkdocs-decrypt-form');
9489
// Adjust password field width to placeholder length
9590
let input = document.getElementById("mkdocs-content-password");
9691
input.setAttribute('size', input.getAttribute('placeholder').length);
97-
{% if encrypted_toc %}
98-
// Decrypt all Table Of Content on the page
99-
var decrypt_toc = function() {
100-
for (i = 0; i < encrypted_toc.length; i++) {
101-
// grab the cipher ToC bundle
102-
var parts = encrypted_toc[i].innerHTML.split(';');
103-
// decrypt it
104-
var content = decrypt_content(
105-
password_input.value,
106-
parts[0],
107-
parts[1],
108-
parts[2]
109-
);
110-
if (content) {
111-
// success; display the decrypted ToC
112-
encrypted_toc[i].innerHTML = content;
113-
encrypted_toc[i].style.display = null;
114-
// any post processing on the decrypted toc should be done here
92+
{% if encrypted_something %}
93+
var encrypted_something = {{ encrypted_something }}
94+
// Decrypt all others elements
95+
var decrypt_somethings = function() {
96+
var html_item = ''
97+
for (const [name, tag] of Object.entries(encrypted_something)) {
98+
if (tag[1] == 'id') {
99+
html_item = [document.getElementById(name)];
100+
} else if (tag[1] == 'class') {
101+
html_item = document.getElementsByClassName(name);
102+
} else {
103+
console.log('Unknow tag html found ...');
104+
}
105+
for (i = 0; i < html_item.length; i++) {
106+
// grab the cipher ToC bundle
107+
var parts = html_item[i].innerHTML.split(';');
108+
// decrypt it
109+
var content = decrypt_content(
110+
password_input.value,
111+
parts[0],
112+
parts[1],
113+
parts[2]
114+
);
115+
if (content) {
116+
// success; display the decrypted ToC
117+
html_item[i].innerHTML = content;
118+
html_item[i].style.display = null;
119+
// any post processing on the decrypted toc should be done here
120+
}
115121
}
116122
}
117123
}
@@ -159,8 +165,8 @@ <h1>{{ summary }}</h1>
159165
if (password_cookie) {
160166
password_input.value = password_cookie
161167
decrypt_action();
162-
{% if encrypted_toc %}
163-
decrypt_toc();
168+
{% if encrypted_something %}
169+
decrypt_somethings();
164170
{% endif %}
165171
}
166172
{% endif %}
@@ -169,8 +175,8 @@ <h1>{{ summary }}</h1>
169175
decrypt_button.onclick = function(event) {
170176
event.preventDefault();
171177
decrypt_action();
172-
{% if encrypted_toc %}
173-
decrypt_toc();
178+
{% if encrypted_something %}
179+
decrypt_somethings();
174180
{% endif %}
175181
};
176182
}
@@ -190,8 +196,8 @@ <h1>{{ summary }}</h1>
190196
{% endif %}
191197
event.preventDefault();
192198
decrypt_action();
193-
{% if encrypted_toc %}
194-
decrypt_toc();
199+
{% if encrypted_something %}
200+
decrypt_somethings();
195201
{% endif %}
196202
}
197203
});

encryptcontent/plugin.py

Lines changed: 35 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class encryptContentPlugin(BasePlugin):
5757
('tag_encrypted_page', mkdocs.config.config_options.Type(bool, default=False)),
5858
('password_button', mkdocs.config.config_options.Type(bool, default=False)),
5959
('password_button_text', mkdocs.config.config_options.Type(string_types, default=str(settings['password_button_text']))),
60-
('encrypted_something', mkdocs.config.config_options.Type(list, default=[])),
60+
('encrypted_something', mkdocs.config.config_options.Type(dict, default={})),
6161
)
6262

6363
def __hash_md5__(self, text):
@@ -167,11 +167,11 @@ def on_pre_build(self, config):
167167
if 'password_button_text' in plugin_config.keys():
168168
password_button_text = plugin_config.get('password_button_text')
169169
setattr(self, 'password_button_text', password_button_text)
170-
# Check if encrypted_something feature is enable: encrypt each elke
171-
setattr(self, 'encrypted_toc', False)
172-
if 'encrypted_toc' in plugin_config.keys():
173-
encrypted_toc = self.config.get('encrypted_toc')
174-
setattr(self, 'encrypted_toc', encrypted_toc)
170+
# Check if encrypted_something feature is enable: encrypt each other html tags targets
171+
setattr(self, 'encrypted_something', {})
172+
if 'encrypted_something' in plugin_config.keys():
173+
encrypted_something = self.config.get('encrypted_something')
174+
setattr(self, 'encrypted_something', encrypted_something)
175175

176176

177177
def on_page_markdown(self, markdown, page, config, **kwargs):
@@ -221,7 +221,7 @@ def on_page_content(self, html, page, config, **kwargs):
221221
if self.tag_encrypted_page:
222222
# Set attribute on page to identify encrypted page on template rendering
223223
setattr(page, 'encrypted', True)
224-
if self.encrypted_toc:
224+
if self.encrypted_something:
225225
# Set attributes on page to retrieve password on POST context
226226
setattr(page, 'password', self.password)
227227
html = self.__encrypt_content__(html)
@@ -237,32 +237,34 @@ def on_post_page(self, output_content, page, config, **kwargs):
237237
:param config: global configuration object
238238
:return: output of rendered template as string
239239
"""
240-
# Limit this process only if encrypted_toc feature is enable *(speedup x4)*
241-
if self.encrypted_toc and hasattr(page, 'encrypted'):
240+
# Limit this process only if encrypted_something feature is enable *(speedup)*
241+
if self.encrypted_something and hasattr(page, 'encrypted') and len(self.encrypted_something) > 0:
242242
soup = BeautifulSoup(output_content, 'html.parser')
243-
toc_search = soup.findAll("nav", { "class" : "mkdocs-encrypted-toc" })
244-
if toc_search is not None and len(toc_search) > 0:
245-
# Loop for multi tags (a.k.a: Mobile and Desktop)
246-
for item in toc_search:
247-
# Remove '\n', ' ' useless content generated by bs4 parsing...
248-
item.contents = [content for content in item.contents if not content in ['\n', ' ']]
249-
# Merge the content in case there are several elements
250-
if len(item.contents) > 1:
251-
merge_item = ''.join([str(s) for s in item.contents])
252-
else:
253-
merge_item = item.contents[0]
254-
# Select childs items on target tags and encrypt all content with page password
255-
ciphertoc_bundle = self.__encrypt_text_aes__(merge_item, page.password)
256-
encrypted_toc = b';'.join(ciphertoc_bundle).decode('ascii')
257-
# Replace initial content with encrypted one
258-
bs4_encrypted_content = BeautifulSoup(encrypted_toc, 'html.parser')
259-
item.contents = [bs4_encrypted_content]
260-
if item.has_attr('style'):
261-
if isinstance(item['style'], list):
262-
item['style'].append("display:none")
243+
for name, tag in self.encrypted_something.items():
244+
#print({'name': name, 'html tag': tag[0], 'type': tag[1]})
245+
something_search = soup.findAll(tag[0], { tag[1]: name })
246+
if something_search is not None and len(something_search) > 0:
247+
# Loop for multi childs tags on target element
248+
for item in something_search:
249+
# Remove '\n', ' ' useless content generated by bs4 parsing...
250+
item.contents = [content for content in item.contents if not content in ['\n', ' ']]
251+
# Merge the content in case there are several elements
252+
if len(item.contents) > 1:
253+
merge_item = ''.join([str(s) for s in item.contents])
263254
else:
264-
item['style'] = item['class'] + "display:none"
265-
else:
266-
item['style'] = "display:none"
267-
output_content = str(soup)
255+
merge_item = item.contents[0]
256+
# Encrypt childs items on target tags with page password
257+
ciphertoc_bundle = self.__encrypt_text_aes__(merge_item, page.password)
258+
encrypted_toc = b';'.join(ciphertoc_bundle).decode('ascii')
259+
# Replace initial content with encrypted one
260+
bs4_encrypted_content = BeautifulSoup(encrypted_toc, 'html.parser')
261+
item.contents = [bs4_encrypted_content]
262+
if item.has_attr('style'):
263+
if isinstance(item['style'], list):
264+
item['style'].append("display:none")
265+
else:
266+
item['style'] = item['class'] + "display:none"
267+
else:
268+
item['style'] = "display:none"
269+
output_content = str(soup)
268270
return output_content

0 commit comments

Comments
 (0)