fontu 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fontu-0.0.1.dist-info/METADATA +52 -0
- fontu-0.0.1.dist-info/RECORD +6 -0
- fontu-0.0.1.dist-info/WHEEL +5 -0
- fontu-0.0.1.dist-info/entry_points.txt +2 -0
- fontu-0.0.1.dist-info/top_level.txt +1 -0
- main.py +410 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fontu
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A CLI tool to shuffle glyphs in a local font and encrypt text (e.g., HTML files) using the shuffled font.
|
|
5
|
+
Author: automatonomy.net
|
|
6
|
+
Author-email: Andy Gajdošík <andreas@gajdosik.org>, Tomáš Zato <tomas@screensaver.gallery>
|
|
7
|
+
Maintainer-email: Andy Gajdošík <andreas@gajdosik.org>
|
|
8
|
+
Project-URL: Homepage, https://codeberg.org/automatonomy/fontu
|
|
9
|
+
Project-URL: Issues, https://codeberg.org/automatonomy/fontu/issues
|
|
10
|
+
Keywords: art,CLI,font,anti-AI,antiAI,AI,encoding
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
16
|
+
Requires-Python: >=3.12
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
Requires-Dist: beautifulsoup4>=4.15
|
|
19
|
+
Requires-Dist: fonttools>=4.63.0
|
|
20
|
+
|
|
21
|
+
# FontU!
|
|
22
|
+
|
|
23
|
+
Simple Python script to:
|
|
24
|
+
1. shuffle characters of the text content of your HTML,
|
|
25
|
+
2. accordingly (in reverse order) shuffle symbols in the font,
|
|
26
|
+
3. add the font into your HTML,
|
|
27
|
+
4. congratz, text contents of your HTML are machine unreadable, yet human can read it just fine.
|
|
28
|
+
|
|
29
|
+
## Problems
|
|
30
|
+
|
|
31
|
+
Text encrypted by FontU will not be readable by screen readers.
|
|
32
|
+
We plan to investigate and fix this problem.
|
|
33
|
+
Maybe we could manipulate the vocal files accordingly?
|
|
34
|
+
If you have experience with screen readers, please let us know.
|
|
35
|
+
We deeply appreciate your feedback and ideas.
|
|
36
|
+
|
|
37
|
+
## Example commands
|
|
38
|
+
|
|
39
|
+
For simple one-step encoding, run `do` subcommand and spefcify input HTML with an input font:
|
|
40
|
+
`python main.py do -i in_html/gajdosik-org_sample.html -f in_fonts/Roboto/Roboto-VariableFont_wdth,wght.ttf`
|
|
41
|
+
|
|
42
|
+
Or alternatively first create a shuffled font and coresponding keymap holding about exact shuffle order:
|
|
43
|
+
`python main.py wys -f in_fonts/Roboto/Roboto-VariableFont_wdth,wght.ttf`
|
|
44
|
+
|
|
45
|
+
Then call `wtg` to use the keymap to encode HTML file and add decoding font to it automatically:
|
|
46
|
+
`python main.py wtg -i in_html/gajdosik-org_sample.html -k private/fontu.json`
|
|
47
|
+
|
|
48
|
+
## Credits
|
|
49
|
+
|
|
50
|
+
Huge thanks to all authors and contributors of [fontTools](https://github.com/fonttools/fonttools).
|
|
51
|
+
|
|
52
|
+
Thanks to MetroByte, their script [getfontchars.py](https://github.com/MetroByte/GetFontChars/blob/main/getfontchars.py) served me a as nice introductory example into `fontTools`.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
main.py,sha256=q9xV34l9qKJ-HYR6DZP-qh8mlGBUM0Fgyu01K4H8nSg,15138
|
|
2
|
+
fontu-0.0.1.dist-info/METADATA,sha256=xLBYU2vaB8bmXS6WzeV9iQWYC6qvOE8ObAw2VOY76fU,2337
|
|
3
|
+
fontu-0.0.1.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
4
|
+
fontu-0.0.1.dist-info/entry_points.txt,sha256=XTO9ZCb9LXVq21IVBTOHWUin3dgr88CAkYLAVpOeWeM,36
|
|
5
|
+
fontu-0.0.1.dist-info/top_level.txt,sha256=ZAMgPdWghn6xTRBO6Kc3ML1y3ZrZLnjZlqbboKXc_AE,5
|
|
6
|
+
fontu-0.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
main
|
main.py
ADDED
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import random
|
|
3
|
+
import os
|
|
4
|
+
import json
|
|
5
|
+
import pathlib
|
|
6
|
+
import shutil
|
|
7
|
+
|
|
8
|
+
from fontTools import ttLib
|
|
9
|
+
from bs4 import BeautifulSoup, element
|
|
10
|
+
|
|
11
|
+
SUPPORTED_FONTS = [".ttf"]
|
|
12
|
+
|
|
13
|
+
# MARK: FONT SHUFFLING
|
|
14
|
+
def shuffle_font(input_font: pathlib.Path, characters: str, seed: int | float | str | bytes | bytearray | None) -> tuple[ttLib.TTFont, dict]:
|
|
15
|
+
"""Get font, shuffle its selected characters and create a contra mapping to this shuffle. Use seed for the shuffle if provided.
|
|
16
|
+
Return the tuple (font, contra_mapping), so we can encode text content of the HTML accordingly.
|
|
17
|
+
"""
|
|
18
|
+
if seed == "":
|
|
19
|
+
seed = None
|
|
20
|
+
input_font = pathlib.Path(input_font).absolute()
|
|
21
|
+
font = ttLib.TTFont(input_font)
|
|
22
|
+
unicode_cmaps = []
|
|
23
|
+
for table in font["cmap"].tables:
|
|
24
|
+
if table.isUnicode():
|
|
25
|
+
unicode_cmaps.append(table)
|
|
26
|
+
|
|
27
|
+
if not unicode_cmaps:
|
|
28
|
+
raise RuntimeError("No Unicode cmap table found in this font.")
|
|
29
|
+
|
|
30
|
+
codepoints = [ord(c) for c in characters]
|
|
31
|
+
print(f"Following characters will be shuffled {codepoints}")
|
|
32
|
+
|
|
33
|
+
source_cmap = unicode_cmaps[0].cmap
|
|
34
|
+
available_codepoints = [cp for cp in codepoints if cp in source_cmap]
|
|
35
|
+
|
|
36
|
+
if len(available_codepoints) < 2:
|
|
37
|
+
raise RuntimeError("Not enough selected characters exist in the font to shuffle.")
|
|
38
|
+
|
|
39
|
+
# Original mapping: Unicode codepoint -> glyph name
|
|
40
|
+
original_mapping = {}
|
|
41
|
+
for cp in available_codepoints:
|
|
42
|
+
original_mapping[cp] = source_cmap[cp]
|
|
43
|
+
|
|
44
|
+
shuffled_codepoints = available_codepoints[:]
|
|
45
|
+
while shuffled_codepoints == available_codepoints:
|
|
46
|
+
random.seed(seed)
|
|
47
|
+
random.shuffle(shuffled_codepoints)
|
|
48
|
+
|
|
49
|
+
new_mapping = {}
|
|
50
|
+
for new_cp, old_cp in zip(shuffled_codepoints, available_codepoints):
|
|
51
|
+
new_mapping[new_cp] = original_mapping[old_cp]
|
|
52
|
+
|
|
53
|
+
for cmap_table in unicode_cmaps:
|
|
54
|
+
for cp, glyph_name in new_mapping.items():
|
|
55
|
+
if cp not in cmap_table.cmap:
|
|
56
|
+
continue
|
|
57
|
+
cmap_table.cmap[cp] = glyph_name
|
|
58
|
+
|
|
59
|
+
contra_mapping = {}
|
|
60
|
+
print("[Character] will be shown as [character]")
|
|
61
|
+
for old_cp, new_cp in zip(available_codepoints, shuffled_codepoints):
|
|
62
|
+
displayed_char = chr(old_cp)
|
|
63
|
+
typed_char = chr(new_cp)
|
|
64
|
+
old = f"{displayed_char!r}({old_cp})"
|
|
65
|
+
new = f"{typed_char!r}({new_cp})"
|
|
66
|
+
print(f" {old:15} -> {new}")
|
|
67
|
+
contra_mapping[displayed_char] = typed_char
|
|
68
|
+
|
|
69
|
+
print("contra_mapping", contra_mapping)
|
|
70
|
+
return font, contra_mapping
|
|
71
|
+
|
|
72
|
+
# MARK: ENCODING
|
|
73
|
+
def encode_text(text: str, mapping: dict):
|
|
74
|
+
"""Encode text based on the mapping."""
|
|
75
|
+
output = ""
|
|
76
|
+
for character in text:
|
|
77
|
+
if character in mapping:
|
|
78
|
+
output = output + mapping[character]
|
|
79
|
+
else:
|
|
80
|
+
output = output + character
|
|
81
|
+
return output
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def encode_html(html_path: pathlib.Path, mapping: dict, font_name: str) -> BeautifulSoup:
|
|
85
|
+
"""Encode HTML file using mapping. Inject font_name as default font. Save the result to out_dir."""
|
|
86
|
+
html_path = pathlib.Path(html_path).absolute()
|
|
87
|
+
with open(html_path, "rt") as f:
|
|
88
|
+
soup = BeautifulSoup(f, 'html.parser')
|
|
89
|
+
|
|
90
|
+
# get text based elements
|
|
91
|
+
elements = soup.find_all(string=True)
|
|
92
|
+
for elem in elements:
|
|
93
|
+
if isinstance(elem, (element.Doctype, element.Comment)):
|
|
94
|
+
continue
|
|
95
|
+
if elem is None or elem.parent is None:
|
|
96
|
+
continue
|
|
97
|
+
if elem.parent.name == "title":
|
|
98
|
+
continue
|
|
99
|
+
encoded = encode_text(elem.string, mapping)
|
|
100
|
+
print(f"{elem.parent.name}\n--{elem}\n->{encoded}\n")
|
|
101
|
+
elem.string.replace_with(encoded)
|
|
102
|
+
|
|
103
|
+
images = soup.find_all("img")
|
|
104
|
+
for image in images:
|
|
105
|
+
image["alt"] = encode_text(image.get("alt", ""), mapping)
|
|
106
|
+
|
|
107
|
+
# INJECT FONT AUTOMATICALLY
|
|
108
|
+
style_tag = soup.new_tag("style")
|
|
109
|
+
style_tag.string = f"""
|
|
110
|
+
@font-face {{
|
|
111
|
+
font-family: "FontuFont";
|
|
112
|
+
src: url("{font_name}") format("truetype");
|
|
113
|
+
font-weight: normal;
|
|
114
|
+
font-style: normal;
|
|
115
|
+
}}
|
|
116
|
+
html {{
|
|
117
|
+
font-family: "FontuFont", sans-serif;
|
|
118
|
+
}}
|
|
119
|
+
"""
|
|
120
|
+
h = soup.find("head")
|
|
121
|
+
if h is not None:
|
|
122
|
+
h.append(style_tag)
|
|
123
|
+
else:
|
|
124
|
+
print("Could not find <head> element in the file, could not append font style.")
|
|
125
|
+
|
|
126
|
+
return soup
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def get_basic_chars():
|
|
130
|
+
"""Get characters from basic Unicode planes: Basic Latin,
|
|
131
|
+
Latin-1 Supplement, Latin Extended-A, Latin Extended-B and IPA Extensions.
|
|
132
|
+
Skip those chars which affects formatting etc., just the simple chars.
|
|
133
|
+
https://codepoints.net/basic_multilingual_plane
|
|
134
|
+
"""
|
|
135
|
+
chars = ""
|
|
136
|
+
for x in range(33, 127):
|
|
137
|
+
chars = chars + chr(x)
|
|
138
|
+
for x in range(161, 688):
|
|
139
|
+
if x == 173:
|
|
140
|
+
continue
|
|
141
|
+
chars = chars + chr(x)
|
|
142
|
+
return chars
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def get_table_dict(table: dict, fonts: list) -> dict:
|
|
146
|
+
"""Format is based on the fontu-js definition."""
|
|
147
|
+
return {
|
|
148
|
+
"table": table,
|
|
149
|
+
"fonts": fonts,
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
# MARK: FILE OPERATIONS
|
|
153
|
+
def save_encoded_html(soup: BeautifulSoup, dest: pathlib.Path):
|
|
154
|
+
dest = pathlib.Path(dest).absolute()
|
|
155
|
+
if not dest.parent.exists():
|
|
156
|
+
os.makedirs(dest.parent, exist_ok=True)
|
|
157
|
+
with open(dest, "wt") as file:
|
|
158
|
+
file.write(str(soup))
|
|
159
|
+
print(f"Saved encoded HTML file to: {dest}")
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def save_shuffled_font(font:ttLib.TTFont, dest: pathlib.Path):
|
|
163
|
+
dest = pathlib.Path(dest).absolute()
|
|
164
|
+
if not dest.parent.exists():
|
|
165
|
+
os.makedirs(dest.parent, exist_ok=True)
|
|
166
|
+
font.save(dest)
|
|
167
|
+
print(f"Saved shuffled font to: {dest}")
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def save_mapping_file(mapping: dict, font_name: str, file_path: pathlib.Path):
|
|
171
|
+
if not file_path.parent.exists():
|
|
172
|
+
os.makedirs(file_path.parent, exist_ok=True)
|
|
173
|
+
with open(file_path, "wt") as file:
|
|
174
|
+
t = get_table_dict(mapping, [font_name] )
|
|
175
|
+
file.write(json.dumps(t))
|
|
176
|
+
print(f"Mapping file successfully saved to {file_path}")
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def read_mapping_file(fp: pathlib.Path):
|
|
180
|
+
fp = pathlib.Path(fp)
|
|
181
|
+
if not fp.exists():
|
|
182
|
+
RuntimeError(f"Cannot read mapping file, file does not exist: {fp}")
|
|
183
|
+
|
|
184
|
+
with open(fp, "rt") as file:
|
|
185
|
+
data = json.load(file)
|
|
186
|
+
|
|
187
|
+
if "table" not in data.keys():
|
|
188
|
+
RuntimeError(f"Mapping file does not contain key 'table'")
|
|
189
|
+
if "fonts" not in data.keys():
|
|
190
|
+
RuntimeError(f"Mapping file does not contain key 'fonts'")
|
|
191
|
+
|
|
192
|
+
return data["table"], data["fonts"]
|
|
193
|
+
|
|
194
|
+
# MARK: CMD FUNCS
|
|
195
|
+
def cmd_what_you_see(args):
|
|
196
|
+
input_font = validate_flag_input_font(args)
|
|
197
|
+
output_json = validate_flag_output_json(args)
|
|
198
|
+
|
|
199
|
+
font, mapping = shuffle_font(input_font, args.chars, args.seed)
|
|
200
|
+
|
|
201
|
+
output_font_name = output_json.stem + input_font.suffix
|
|
202
|
+
output_font_path = os.path.join(output_json.parent, output_font_name)
|
|
203
|
+
save_shuffled_font(font, output_font_path)
|
|
204
|
+
save_mapping_file(mapping, output_font_name, output_json)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def cmd_what_they_get(args):
|
|
208
|
+
html_path = validate_flag_input_html(args)
|
|
209
|
+
out_dir = validate_flag_out_dir(args)
|
|
210
|
+
keymap_path = validate_flag_keymap(args)
|
|
211
|
+
|
|
212
|
+
mapping, fonts = read_mapping_file(keymap_path)
|
|
213
|
+
|
|
214
|
+
font = fonts[0] # TODO: discuss with Tomas if we really want multiple fonts.
|
|
215
|
+
input_font = keymap_path.parent.joinpath(font)
|
|
216
|
+
output_font = out_dir.joinpath(font)
|
|
217
|
+
shutil.copy(input_font, output_font)
|
|
218
|
+
|
|
219
|
+
soup = encode_html(html_path, mapping, font)
|
|
220
|
+
save_encoded_html(soup, out_dir.joinpath(html_path.name))
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def cmd_do(args):
|
|
224
|
+
input_font = validate_flag_input_font(args)
|
|
225
|
+
input_html = validate_flag_input_html(args)
|
|
226
|
+
out_dir = validate_flag_out_dir(args)
|
|
227
|
+
font_name = f"fontu-{input_font.name}"
|
|
228
|
+
|
|
229
|
+
font, mapping = shuffle_font(input_font, args.chars, args.seed)
|
|
230
|
+
save_shuffled_font(font, out_dir.joinpath(font_name))
|
|
231
|
+
|
|
232
|
+
soup = encode_html(input_html, mapping, font_name)
|
|
233
|
+
save_encoded_html(soup, out_dir.joinpath(input_html.name))
|
|
234
|
+
|
|
235
|
+
# MARK: VALIDATIONS
|
|
236
|
+
def validate_flag_input_font(args) -> pathlib.Path:
|
|
237
|
+
input_font = pathlib.Path(args.font).absolute()
|
|
238
|
+
if not input_font.is_file():
|
|
239
|
+
raise RuntimeError("flag -font needs to be a path to a font file.")
|
|
240
|
+
if input_font.suffix.lower() not in SUPPORTED_FONTS:
|
|
241
|
+
raise RuntimeError(f"flag -font needs to be one of supported fonts: {SUPPORTED_FONTS}")
|
|
242
|
+
return input_font
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def validate_flag_input_html(args) -> pathlib.Path:
|
|
246
|
+
path = pathlib.Path(args.input_html).absolute()
|
|
247
|
+
if not path.exists():
|
|
248
|
+
raise RuntimeError(f"flag -input-html {path} needs to be an existing file.")
|
|
249
|
+
if path.is_dir():
|
|
250
|
+
raise RuntimeError(f"flag -input-html {path} needs to be a path to a HTML file, not directory.")
|
|
251
|
+
return path
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def validate_flag_out_dir(args) -> pathlib.Path:
|
|
255
|
+
path = pathlib.Path(args.out_dir).absolute()
|
|
256
|
+
if not path.exists():
|
|
257
|
+
os.makedirs(path, exist_ok=True)
|
|
258
|
+
if not path.is_dir():
|
|
259
|
+
raise RuntimeError(f"flag -out-dir {path} is not a directory.")
|
|
260
|
+
return path
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def validate_flag_keymap(args) -> pathlib.Path:
|
|
264
|
+
path = pathlib.Path(args.keymap).absolute()
|
|
265
|
+
if not path.exists():
|
|
266
|
+
raise RuntimeError(f"flag -keymap {path} needs to exist.")
|
|
267
|
+
if path.is_dir():
|
|
268
|
+
raise RuntimeError(f"flag -keymap {path} cannot be a directory.")
|
|
269
|
+
return path
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def validate_flag_output_json(args) -> pathlib.Path:
|
|
273
|
+
path = pathlib.Path(args.output).absolute()
|
|
274
|
+
if path.is_dir():
|
|
275
|
+
raise RuntimeError("flag -output needs to be a path to a JSON file, not a directory.")
|
|
276
|
+
if path.suffix != ".json":
|
|
277
|
+
raise RuntimeError("flag -output needs to be a JSON file.")
|
|
278
|
+
return path
|
|
279
|
+
|
|
280
|
+
# MARK: MAIN
|
|
281
|
+
if __name__ == "__main__":
|
|
282
|
+
parser = argparse.ArgumentParser(
|
|
283
|
+
prog='fontu',
|
|
284
|
+
description='Encrypt the HTML text content and create a font which visually decrypts it. '
|
|
285
|
+
'The (plain)text is unreadable for the machines, but readable by humans if it is rendered using the one specific font.',
|
|
286
|
+
epilog='What you see is not what they get.'
|
|
287
|
+
)
|
|
288
|
+
subparser = parser.add_subparsers(
|
|
289
|
+
title='subcommands',
|
|
290
|
+
required=True,
|
|
291
|
+
description='',
|
|
292
|
+
help='',
|
|
293
|
+
metavar='',
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
# MARK: DO
|
|
297
|
+
do_help = ("Do the encoding process (wys and wtg) in a single step. "
|
|
298
|
+
"Take the specified font and shuffle its characters, then shuffle the text in the HTML in opposite direction. "
|
|
299
|
+
"This result in an HTML unreadable to machines, but readable to human eyes."
|
|
300
|
+
)
|
|
301
|
+
do = subparser.add_parser(
|
|
302
|
+
name="do",
|
|
303
|
+
aliases=["what-you-see-is-not-what-they-get", "wtf"],
|
|
304
|
+
help=do_help,
|
|
305
|
+
description=do_help + " " +
|
|
306
|
+
"This command does not save the mapping file. "
|
|
307
|
+
"In order to encode multiple HTML files using the same font, please use first 'wys' to get the mapping and then 'wtg' apply mapping to multiple files.",
|
|
308
|
+
)
|
|
309
|
+
do.add_argument(
|
|
310
|
+
"-i", "--input-html", type=str,
|
|
311
|
+
default="in_html/gajdosik-org_sample.html",
|
|
312
|
+
help="Path to input HTML file. "
|
|
313
|
+
"Text content of it will be encrypted using the Keymap. "
|
|
314
|
+
"A compatible decrypting font will be added to the style of the HTML."
|
|
315
|
+
)
|
|
316
|
+
do.add_argument(
|
|
317
|
+
"-f", "--font", type=str,
|
|
318
|
+
default="in_fonts/Roboto/Roboto-VariableFont_wdth,wght.ttf",
|
|
319
|
+
help="Path to an input font which will be shuffled. "
|
|
320
|
+
"Resulting font comes to the same directory as OUTPUT, sharing its name."
|
|
321
|
+
)
|
|
322
|
+
do.add_argument(
|
|
323
|
+
"-c", "--chars", type=str,
|
|
324
|
+
default=get_basic_chars(),
|
|
325
|
+
help="String of characters which should be used for shuffling. "
|
|
326
|
+
"If nothing is provided default string containing extended set of latin characters is used. "
|
|
327
|
+
"Characters unavailable in the font are skipped."
|
|
328
|
+
)
|
|
329
|
+
do.add_argument(
|
|
330
|
+
"-o", "--out-dir", type=str,
|
|
331
|
+
default="public",
|
|
332
|
+
help="Path to output directory where the encrypted HTML file will be saved. "
|
|
333
|
+
"The decryption font will be copied there as well."
|
|
334
|
+
)
|
|
335
|
+
do.add_argument(
|
|
336
|
+
"-s", "--seed", type=str,
|
|
337
|
+
help="Seed to be used for the random shuffling. Same seed should provide the same results. "
|
|
338
|
+
"If no seed is provided a default Python seed is used, which is a current time or random source from the OS."
|
|
339
|
+
)
|
|
340
|
+
do.set_defaults(func=cmd_do)
|
|
341
|
+
|
|
342
|
+
# MARK: WHAT-YOU-SEE
|
|
343
|
+
wys_help = (
|
|
344
|
+
"Create decryption font and map which can be later used to reproducibly encrypt text content of HTML files. "
|
|
345
|
+
"Resulting font and mapping can be used by <wtg> subcommand to encrypt HTML files."
|
|
346
|
+
)
|
|
347
|
+
wys = subparser.add_parser(
|
|
348
|
+
name="what-you-see",
|
|
349
|
+
aliases=["wys", "create"],
|
|
350
|
+
help=wys_help,
|
|
351
|
+
description=wys_help,
|
|
352
|
+
)
|
|
353
|
+
wys.add_argument(
|
|
354
|
+
"-f", "--font", type=str,
|
|
355
|
+
default="in_fonts/Roboto/Roboto-VariableFont_wdth,wght.ttf",
|
|
356
|
+
help="Path to an input font which will be shuffled. "
|
|
357
|
+
"Resulting font comes to the same directory as OUTPUT, sharing its name."
|
|
358
|
+
)
|
|
359
|
+
wys.add_argument(
|
|
360
|
+
"-c", "--chars", type=str,
|
|
361
|
+
default=get_basic_chars(),
|
|
362
|
+
help="String of characters which should be used for shuffling. "
|
|
363
|
+
"If nothing is provided default string containing extended set of latin characters is used. "
|
|
364
|
+
"Characters unavailable in the font are skipped."
|
|
365
|
+
)
|
|
366
|
+
wys.add_argument(
|
|
367
|
+
"-o", "--output", type=str,
|
|
368
|
+
default="private/fontu.json",
|
|
369
|
+
help="Path where resulting keymap JSON file should be saved. "
|
|
370
|
+
"It will contain the mapping of how characters should be shuffled. "
|
|
371
|
+
"Next to it the shuffled font with the same name as the mapping JSON will be saved."
|
|
372
|
+
)
|
|
373
|
+
wys.add_argument(
|
|
374
|
+
"-s", "--seed", type=str,
|
|
375
|
+
help="Seed to be used for the random shuffling. Same seed should provide the same results. "
|
|
376
|
+
"If no seed is provided a default Python seed is used, which is a current time or random source from the OS."
|
|
377
|
+
)
|
|
378
|
+
wys.set_defaults(func=cmd_what_you_see)
|
|
379
|
+
|
|
380
|
+
# MARK: WHAT THEY GET
|
|
381
|
+
wtg_help = "Encode the text content of specified HTML file. Add decryption font to it automatically."
|
|
382
|
+
wtg = subparser.add_parser(
|
|
383
|
+
name="what-they-get",
|
|
384
|
+
aliases=["wtg", "encode"],
|
|
385
|
+
help=wtg_help,
|
|
386
|
+
description=wtg_help,
|
|
387
|
+
)
|
|
388
|
+
wtg.add_argument(
|
|
389
|
+
"-i", "--input-html", type=str,
|
|
390
|
+
default="in_html/gajdosik-org_sample.html",
|
|
391
|
+
help="Path to input HTML file. "
|
|
392
|
+
"Text content of it will be encrypted using the Keymap. "
|
|
393
|
+
"A compatible decrypting font will be added to the style of the HTML."
|
|
394
|
+
)
|
|
395
|
+
wtg.add_argument(
|
|
396
|
+
"-k", "--keymap", type=str,
|
|
397
|
+
default="private/fontu.json",
|
|
398
|
+
help="Path to input keymap JSON file. "
|
|
399
|
+
"It contains information how to shuffle the characters and list of all fonts, which were shuffled in opossite way."
|
|
400
|
+
)
|
|
401
|
+
wtg.add_argument(
|
|
402
|
+
"-o", "--out-dir", type=str,
|
|
403
|
+
default="public",
|
|
404
|
+
help="Path to output directory where the encrypted HTML file will be saved. "
|
|
405
|
+
"The decryption font will be copied there as well."
|
|
406
|
+
)
|
|
407
|
+
wtg.set_defaults(func=cmd_what_they_get)
|
|
408
|
+
|
|
409
|
+
args = parser.parse_args()
|
|
410
|
+
args.func(args)
|