123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- {{/*
- ## Hugo Encrypt
- ### Params:
- - `password`:
- require param
- - Simple
- {{< hugo-encrypt "your password" >}}
- your content
- {{< /hugo-encrypt >}}
- */}}
- {{/* DEFAULTS */}}
- {{ $_hugo_config := `{ "version": 1 }` }}
- <hugo-encrypt>
- {{ if .Get 0 }}
- {{- $passphrase := $.Scratch.Set "passphrase" (.Get 0) -}}
- {{ else if .Site.Params.Password }}
- {{- $passphrase := $.Scratch.Set "passphrase" .Site.Params.Password -}}
- {{ else }}
- {{- $passphrase -}}
- {{ end }}
- <p>{{ i18n "protectedbypwd" }}</p>
- <div class='hugo-encrypt-form'>
- <input
- class="hugo-encrypt-input"
- id="hugo-encrypt-password"
- placeholder='{{ i18n "inputpassword" }}'
- />
- <input
- class="hugo-encrypt-button"
- type="button"
- value='{{ i18n "decrypt" }}'
- id="button" onclick="hugoDecrypt(document.getElementById('hugo-encrypt-password').value,'input')"
- />
- </div>
- <cipher-text data-password="{{ $.Scratch.Get "passphrase" }}" style="display:none;">
- <!-- Do not indent the following two lines -->
- {{ .Inner }}
- </cipher-text>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/core.js"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/sha1.js"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/1.9.0/showdown.min.js"></script>
- <script>
- let cipher = document.getElementsByTagName("cipher-text")[0];
- const storageKey = location.pathname + "password";
- const userStorage = {{ if .Site.Params.hugoEncryptStorage }} window['{{.Site.Params.hugoEncryptStorage}}Storage'] {{ else }} localStorage {{ end }};
- /**
- * Encodes a utf8 string as a byte array.
- * @param {String} str
- * @returns {Uint8Array}
- */
- function str2buf(str) {
- return new TextEncoder("utf-8").encode(str);
- }
- /**
- * Decodes a byte array as a utf8 string.
- * @param {Uint8Array} buffer
- * @returns {String}
- */
- function buf2str(buffer) {
- return new TextDecoder("utf-8").decode(buffer);
- }
- /**
- * Decodes a string of hex to a byte array.
- * @param {String} hexStr
- * @returns {Uint8Array}
- */
- function hex2buf(hexStr) {
- return new Uint8Array(hexStr.match(/.{2}/g).map(h => parseInt(h, 16)));
- }
- /**
- * Given a passphrase, this generates a crypto key
- * using `PBKDF2` with SHA256 and 1000 iterations.
- * If no salt is given, a new one is generated.
- * The return value is an array of `[key, salt]`.
- * @param {String} passphrase
- * @param {UInt8Array} salt [salt=random bytes]
- * @returns {Promise<[CryptoKey,UInt8Array]>}
- */
- function deriveKey(passphrase, salt) {
- salt = salt || crypto.getRandomValues(new Uint8Array(8));
- return crypto.subtle
- .importKey("raw", str2buf(passphrase), "PBKDF2", false, ["deriveKey"])
- .then(key =>
- crypto.subtle.deriveKey(
- { name: "PBKDF2", salt, iterations: 1000, hash: "SHA-256" },
- key,
- { name: "AES-GCM", length: 256 },
- false,
- ["encrypt", "decrypt"],
- ),
- )
- .then(key => [key, salt]);
- }
- /**
- * Given a key and ciphertext (in the form of a string) as given by `encrypt`,
- * this decrypts the ciphertext and returns the original plaintext
- * @param {String} passphrase
- * @param {String} saltIvCipherHex
- * @returns {Promise<String>}
- */
- function decrypt(passphrase, saltIvCipherHex) {
- const [salt, iv, data] = saltIvCipherHex.split("-").map(hex2buf);
- return deriveKey(passphrase, salt)
- .then(([key]) => crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, data))
- .then(v => buf2str(new Uint8Array(v)));
- }
- /**
- * Needed to convert markdown within the decrypted text to html
- */
- function interpreteMarkdown(input) {
- var converter = new showdown.Converter()
- return converter.makeHtml(input)
- }
- /**
- * @name:hugoDecrypt
- * @description: judge the password ,and decrypt post
- * @param {String} password
- * @param {String} type
- */
- const hugoDecrypt = function(password, type) {
- try {
- decrypt(password, cipher.innerText).then(function(res) {
- /**
- * calculate sha1 of decrypted text and check if it
- * matches the sha1 at the bottom of the decrypted text
- * to get the same hash that was added during encryption we
- * need to remove the last line
- */
- var hash = CryptoJS.SHA1(res.replace(/\r?\n?[^\r\n]*$/, ""));
- var result = CryptoJS.enc.Hex.stringify(hash);
- if ( res.includes(result) ) {
- cipher.parentElement.outerHTML = interpreteMarkdown(res);
- userStorage.setItem(storageKey, password);
- document.getElementById("sha1sum").innerHTML = "sha1: " + result;
- } else {
- if (type === "input") {
- alert('{{ i18n "wrongpwd" }}');
- } else if (type === "storage") {
- userStorage.removeItem(storageKey);
- }
- }
- });
- } catch (error) {
- if (type === "input") {
- alert('{{ i18n "wrongpwd" }}');
- } else if (type === "storage") {
- userStorage.removeItem(location.pathname + "password");
- }
- }
- };
- </script>
- <script>
- window.onload = () => {
- if (userStorage.getItem(storageKey)) {
- hugoDecrypt(userStorage.getItem(storageKey), "storage");
- }
- };
- </script>
- </hugo-encrypt>
|