Skip to content

Commit ce9a7e7

Browse files
committed
sign generated encrypted pages and used javascript files with Ed25519.
1 parent f172b1d commit ce9a7e7

File tree

1 file changed

+53
-11
lines changed

1 file changed

+53
-11
lines changed

encryptcontent/plugin.py

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ class encryptContentPlugin(BasePlugin):
9595
('translations', config_options.Type(dict, default={}, required=False)),
9696
('hash_filenames', config_options.Type(dict, default={}, required=False)),
9797
('kdf_pow', config_options.Type(int, default=int(4))),
98-
('sign_files', config_options.Type(bool, default=False)),
98+
('sign_files', config_options.Type(string_types, default=None)),
9999
('sign_key', config_options.Type(string_types, default='encryptcontent.key')),
100100
# legacy features, doesn't exist anymore
101101
)
@@ -124,13 +124,20 @@ def __download_and_check__(self, filename, url, hash):
124124
logger.error('Error downloading asset "' + filename.name + '" hash mismatch!')
125125
os._exit(1)
126126

127-
def __sign_file__(self, fname, key):
127+
def __sign_file__(self, fname, url, key):
128128
h = SHA512.new()
129-
with open(fname, "rb") as f:
130-
for chunk in iter(lambda: f.read(4096), b""):
131-
h.update(chunk)
129+
if fname:
130+
with open(fname, "rb") as f:
131+
for chunk in iter(lambda: f.read(4096), b""):
132+
h.update(chunk)
133+
else:
134+
with urlopen(url) as response:
135+
h.update(response.read())
132136
signer = eddsa.new(key, 'rfc8032')
133-
return base64.b64encode(signer.sign(h)).decode()
137+
return (
138+
url,
139+
base64.b64encode(signer.sign(h)).decode()
140+
)
134141

135142
def __encrypt_key__(self, key, password, iterations):
136143
""" Encrypts key with PBKDF2 and AES-256. """
@@ -414,17 +421,20 @@ def on_config(self, config, **kwargs):
414421
self.setup['level_keystore'][level] = new_entry
415422

416423
if self.config['sign_files']:
417-
if not exists(self.config['sign_key']):
418-
logger.debug('Generating signing key and saving to "{file}".'.format(file=str(self.config['sign_key'])))
424+
configpath = Path(config['config_file_path']).parents[0]
425+
sign_key_path = configpath.joinpath(self.config['sign_key'])
426+
if not exists(sign_key_path):
427+
logger.info('Generating signing key and saving to "{file}".'.format(file=str(self.config['sign_key'])))
419428
key = ECC.generate(curve='Ed25519')
420429
self.setup['sign_key'] = key
421-
with open(self.config['sign_key'],'wt') as f:
430+
with open(sign_key_path,'wt') as f:
422431
f.write(key.export_key(format='PEM'))
423432
else:
424-
logger.debug('Reading signing key from "{file}".'.format(file=str(self.config['sign_key'])))
425-
with open(self.config['sign_key'],'rt') as f:
433+
logger.info('Reading signing key from "{file}".'.format(file=str(self.config['sign_key'])))
434+
with open(sign_key_path,'rt') as f:
426435
key = ECC.import_key(f.read())
427436
self.setup['sign_key'] = key
437+
self.setup['files_to_sign'] = []
428438

429439
def on_pre_build(self, config, **kwargs):
430440
"""
@@ -735,6 +745,12 @@ def on_post_page(self, output_content, page, config, **kwargs):
735745
self.setup['locations'][location] = page.encryptcontent['key']
736746
delattr(page, 'encryptcontent')
737747

748+
if self.config['sign_files']:
749+
new_entry = {}
750+
new_entry['file'] = Path(config.data["site_dir"] + "/" + page.file.dest_uri)
751+
new_entry['url'] = config.data["site_url"] + page.file.url
752+
self.setup['files_to_sign'].append(new_entry)
753+
738754
return output_content
739755

740756
def on_post_build(self, config, **kwargs):
@@ -749,6 +765,21 @@ def on_post_build(self, config, **kwargs):
749765
with open(decrypt_js_path, "w") as file:
750766
file.write(self.__generate_decrypt_js__())
751767

768+
if self.config['sign_files']:
769+
new_entry = {}
770+
new_entry['file'] = decrypt_js_path
771+
new_entry['url'] = config.data["site_url"] + '/assets/javascripts/decrypt-contents.js'
772+
self.setup['files_to_sign'].append(new_entry)
773+
for jsurl in JS_LIBRARIES:
774+
new_entry = {}
775+
if self.config['selfhost']:
776+
new_entry['file'] = Path(config.data["site_dir"] + '/assets/javascripts/cryptojs/' + jsurl[0].rsplit('/',1)[1])
777+
new_entry['url'] = config.data["site_url"] + '/assets/javascripts/cryptojs/' + jsurl[0].rsplit('/',1)[1]
778+
else:
779+
new_entry['file'] = ""
780+
new_entry['url'] = "https:" + jsurl[0]
781+
self.setup['files_to_sign'].append(new_entry)
782+
752783
self.setup['password_keystore'].clear()
753784
self.setup['obfuscate_keystore'].clear()
754785
self.setup['level_keystore'].clear()
@@ -796,3 +827,14 @@ def on_post_build(self, config, **kwargs):
796827
' Your weakest password only got {spied_on} bits of entropy, if someone watched you while typing'
797828
' (and a maximum of {secret} bits total)!'.format(spied_on = math.ceil(self.setup['min_enttropy_spied_on']), secret = math.ceil(self.setup['min_enttropy_secret']))
798829
)
830+
831+
if self.config['sign_files']:
832+
signatures = []
833+
for file in self.setup['files_to_sign']:
834+
signatures.append(
835+
self.__sign_file__(file['file'], file['url'], self.setup['sign_key'])
836+
)
837+
if signatures:
838+
sign_file_path = Path(config.data["site_dir"] + '/' + self.config['sign_files'])
839+
with open(sign_file_path, "w") as file:
840+
file.write(json.dumps(signatures))

0 commit comments

Comments
 (0)