diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 14653cd..44dbbc0 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,13 +1,13 @@ ## Frameworks PR Checklist -Thank you for contributing to the Security Frameworks! Before you open a PR, make sure to read [information for contributors](https://framework.securityalliance.org/book/contribute/contribute.html) and take a look at following checklist: +Thank you for contributing to the Security Frameworks! Before you open a PR, make sure to read [information for contributors](https://framework.securityalliance.org/book/contribute/contribute.html) and take a look at the following checklist: - [ ] Describe your changes, substitute this text with the information -- [ ] If you are touching an existing piece of content, ask the original creator for review +- [ ] If you are touching an existing piece of content, ask the original creator for review - [ ] If you need feedback for your content from wider community, share the PR in our Discord -- [ ] Review changes to ensure there are no typos, see instructions bellow +- [ ] Review changes to ensure there are no typos, see instructions below - + + + + + + + + + + diff --git a/theme/index.hbs b/theme/index.hbs index 94c5344..d7d6dfc 100644 --- a/theme/index.hbs +++ b/theme/index.hbs @@ -52,100 +52,9 @@ {{/if}} - - - +
-
-

- This is a work in progress and not a release. We're looking for volunteers. - See Issues to know how to collaborate. -

-
+
+

+ This is a work in progress and not a release. We're looking for volunteers. + See Issues to know how to collaborate. +

+
{{> header}} @@ -298,6 +207,9 @@ {{/if}} + + +
@@ -456,234 +368,5 @@ {{/if}}
- diff --git a/theme/main.js b/theme/main.js new file mode 100644 index 0000000..40217d2 --- /dev/null +++ b/theme/main.js @@ -0,0 +1,235 @@ +/** +* Create a tag element +* @param {string} tag +*/ +function createTagElement(tag) { + const li = document.createElement('li'); + const isChecked = localStorage.getItem(`tag_${tag}`) === 'true'; + li.setAttribute('role', 'option'); + li.innerHTML = ` + + `; + return li; +} + +/** +* Populate the tagList element with tags +* @param {HTMLElement} tagList +* @param {string[]} tags +* @param {string} filter +*/ +function populateTags(tagList, tags, filter = '') { + tagList.innerHTML = ''; + tags.filter(tag => tag.toLowerCase().includes(filter.toLowerCase())) + .forEach(tag => { + tagList.appendChild(createTagElement(tag)); + }); +} + +/** +* Highlight sidebar links based on selected tags +*/ +function highlightSidebarLinks() { + const sidebarLinks = document.querySelectorAll('#sidebar a'); + sidebarLinks.forEach(link => { + link.classList.remove("selected"); + }); + + const tagsDropdown = document.getElementById('tags-dropdown'); + const selectedTags = Object.keys(localStorage) + .filter(key => key.startsWith('tag_') && localStorage.getItem(key) === 'true') + .map(key => key.replace('tag_', '')); + + // Filter pages by AND selected tags + let selectedPages = new Set(window.tagsData[selectedTags[0]] || []); + for (const tag of selectedTags.slice(1)) { + const pages = new Set(window.tagsData[tag] || []); + selectedPages = new Set([...selectedPages].filter(x => pages.has(x))); + if (selectedPages.size === 0) { + break; + } + } + + // Highlight selected pages + selectedPages.forEach(page => { + const link = document.querySelector(`#sidebar #toc a[href$="${page}"]`); + if (link) { + link.classList.add("selected"); + anySelected = true; + } + }); + + if (selectedTags.length === 0) { + document.getElementById("sidebar").classList.remove("filtered"); + } else { + document.getElementById("sidebar").classList.add("filtered"); + } + + // Filter pages by OR selected tags + // let anySelected = false; + // selectedTags.forEach(tag => { + // const pages = window.tagsData[tag] || []; + // pages.forEach(page => { + // const link = document.querySelector(`#sidebar a[href$="${page}"]`); + // if (link) { + // link.classList.add("selected"); + // anySelected = true; + // } + // }); + // }); +} + +/** + * Populates the per-page tags + * @param {[key: string]: string} tagColors + */ +function createPageTags(tagColors) { + const tagLines = Array.from(document.querySelectorAll('p')).filter(line => line.textContent.includes("tag:")); + tagLines.forEach(line => { + const tagText = line.textContent; + if (tagText.includes('tag: [')) { + const tagContent = tagText.split('[')[1].split(']')[0].trim(); + const tags = tagContent.split(',').map(tag => tag.trim()); + const tagLabels = tags.map(tag => { + const hexColor = tagColors[tag] + return ` + + + ${tag} + `; + }); + line.innerHTML = tagLabels.join(' '); + } + }); +} + +/** + * Populates the searchable tags in the tags dropdown + */ +function createSearchableTags(tagsData) { + const tags = Object.keys(tagsData).sort((a, b) => { return ('' + a).localeCompare(b); }); + const tagsList = document.getElementById('tags-list'); + + populateTags(tagsList, tags); + highlightSidebarLinks(); +} + +document.addEventListener('DOMContentLoaded', function () { + updateBookmarkIcon(); + + //* Initialize per-page tags + fetch(path_to_root + 'theme/tagscolors.json') + .then(response => response.json()) + .then(data => { + window.tagsColors = data; + createPageTags(data); + }) + + //* Initialize searchable tags + fetch(path_to_root + 'theme/tagsindex.json') + .then(response => response.json()) + .then(data => { + window.tagsData = data; + addBookmarkTags(); + createSearchableTags(data); + }) + .catch(error => { + console.error('Error loading or parsing tagsindex.json:', error); + }); + + //* Setup event listeners for dropdowns & tags + const tagsToggle = document.getElementById('tags-toggle'); + const tagsDropdown = document.getElementById('tags-dropdown'); + const tagSearch = document.getElementById('tag-search'); + const tagsList = document.getElementById('tags-list'); + + // On click on tags dropdown button + tagsToggle.addEventListener('click', function (event) { + event.stopPropagation(); + const isExpanded = this.getAttribute('aria-expanded') === 'true'; + this.setAttribute('aria-expanded', !isExpanded); + tagsDropdown.classList.toggle('hidden'); + if (!isExpanded) { + tagSearch.focus(); + } + }); + + // On click on anything except for the tags dropdown + document.addEventListener('click', function (event) { + if (!tagsDropdown.contains(event.target) && event.target !== tagsToggle) { + tagsToggle.setAttribute('aria-expanded', 'false'); + tagsDropdown.classList.add('hidden'); + } + }); + + // On search for a tag + tagSearch.addEventListener('input', function () { + populateTags(tagsList, window.tagsData, this.value); + }); + + // On select a tag + tagsList.addEventListener('change', function (event) { + if (event.target.type === 'checkbox') { + const selectedTag = event.target.value; + const isChecked = event.target.checked; + localStorage.setItem(`tag_${selectedTag}`, isChecked); + highlightSidebarLinks(); + } + }); +}); + +const bookmarkPrefix = "bookmarks_"; + +// Bookmarks or unbookmarks the current page +function bookmarkPage() { + const pagePath = getPathname(); + const title = document.title.replace(" - Security Frameworks by SEAL", "").replace(".", ""); + + if (localStorage.getItem(`${bookmarkPrefix}${pagePath}`)) { + localStorage.removeItem(`${bookmarkPrefix}${pagePath}`); + } else { + localStorage.setItem(`${bookmarkPrefix}${pagePath}`, title); + } + + updateBookmarkIcon(); + addBookmarkTags(); + highlightSidebarLinks(); +} + +// Adds all the bookmarks currently stored in localStorage to the tagsData +function addBookmarkTags() { + if (!window.tagsData) { + return + } + window.tagsData["Bookmarked"] = []; + + for (let i = 0; i < localStorage.length; i++) { + const key = localStorage.key(i); + if (key.startsWith(bookmarkPrefix)) { + const pagePath = key.replace(bookmarkPrefix, ""); + window.tagsData["Bookmarked"].push(pagePath); + } + } +} + +// Update the bookmark icon +function updateBookmarkIcon() { + const bookmarkButton = document.getElementById('bookmark-button'); + const pagePath = getPathname(); + + if (localStorage.getItem(`${bookmarkPrefix}${pagePath}`)) { + bookmarkButton.classList.add("fa-bookmark"); + bookmarkButton.classList.remove("fa-bookmark-o"); + } else { + bookmarkButton.classList.add("fa-bookmark-o"); + bookmarkButton.classList.remove("fa-bookmark"); + } +} + +// Gets the path name in the same style as the tagsData +function getPathname() { + return window.location.pathname.replace("/", ""); +} \ No newline at end of file diff --git a/theme/tags_generator.js b/theme/tags_generator.js index 4594f55..9be61df 100644 --- a/theme/tags_generator.js +++ b/theme/tags_generator.js @@ -75,9 +75,9 @@ function tagsGenerator(srcDir, outputDir) { } function generateColor(tag) { - const length = tag.length; - const hex = (length * 1234567).toString(16).slice(0, 6); - return `#${hex.padEnd(6, '0')}`; + const crypto = require("crypto"); + const hex = crypto.createHash("sha1").update(tag).digest("hex").slice(0, 6); + return `#${hex}`; } walkDir(srcDir); @@ -86,13 +86,18 @@ function tagsGenerator(srcDir, outputDir) { console.log(`Creating output directory: ${outputDir}`); fs.mkdirSync(outputDir, { recursive: true }); } - + console.log(`Writing tags to file: ${tagsFile}`); fs.writeFileSync(tagsFile, JSON.stringify(tags, null, 2)); - + + let existingColouredTags = {}; + if (fs.existsSync(colorsFile)) { + existingColouredTags = JSON.parse(fs.readFileSync(colorsFile, "utf8")); + } + const tagColors = {}; for (const tag in tags) { - tagColors[tag] = generateColor(tag); + tagColors[tag] = existingColouredTags[tag] || generateColor(tag); } console.log(`Writing tag colors to file: ${colorsFile}`); diff --git a/wordlist.txt b/wordlist.txt index baf9ee8..206c708 100644 --- a/wordlist.txt +++ b/wordlist.txt @@ -1,79 +1,254 @@ personal_ws-1.1 en 10000 utf-8 +aaaabbbb +abcdef +Acknowledgement Acunetix Aeón Aereal +AES AFL +AKAMAI +Analytics anonymization +Anonymize +Ansible +assignees +authenticator +Authy backdoors +Binance +Biometric +BIP blockchain +Bot's +BTC +Bugcrowd +BYOK Captcha +CCPA +CEX Checkmarx +Checkov +CIS +CISA +Clippy +Cloudflare +CloudSploit +COBIT codebase +Coinbase +collab +Comodo +Config +Cooldown Crypto cryptocurrencies cryptocurrency cryptographic +CSA +CSEK +CSRF +curation +curations +customizable +CyberSec Cybersecurity +DAI dapp +Darknet DAST +decrpyt +decrypt DeFi +Dependabot +Deseat Devops DevSecOps +DLP DNS DNSSEC +DRT +DSS Dyno +EE +Efani +encrypt +Enigmail EOA EOAs +ETH Ethereum Etherscan +Ethlint +Excalidraw executables +FDE +fedcba Fernández +Fi Fredrik Fuzzer Fuzzers Gapped GCP GDPR +Ghostery +gist +gists +Gmail +GOkart +Golang +Golangci +Gosec GPG +Hackenproof +HashiCorp +HIDS HIPAA +HSM +HTTPS +IAM +IAPP +IAST +IDOR +IDPS +IEC +Immunefi +Imperva +incentivize +inevitableeth +influencer Integrations +IPFS +IRP +IRT +JEA +JIT +KeepAss +KMS lifecycle LLVM +LUKS +Mailvelope Matías +MDM +MEE Mehdi +Middleware +misconfiguration +misconfigurations +Mitigation +Mitigations +Mortem +MTTD +MTTR +MullvadVPN multisig Multisignature +MVNO Mythril Nano +NIST +NordVPN +npm +OAuth +Openchain +OpenSCAP OWASP +passcode passcodes +PCI +Phalcon +PII +pre +Pretexting pseudonymization +Qubes +Qwertycards RBAC +RDP +recoverability reentrancy +repo +reputational +Revolut SAST scalable +Scalability +SDLC Sebastián +SED +SEDs +Semgrep sexualized Shamir +Shamir's SIEM +SMS +Snyk socio +SOE Solhint Solidity SonarQube +Spokeo +Squarespace SRE +SSID +SSL +SSO +StackDriver +Stormcast +Surfshark Svantes +Symantec +TDE +Terraform +Terrascan +tfsec +Threema +timeframe +timeframes TLS +TOTP +TPM Trezor +TVL +TXT +UI underflows Unrekt +untrusted +USDC Veracode +Vercel +VLAN +VLANs VPC VPN WAF +walletcompare +Wargames +whitehat +Whitepages whitepapers WHOIS +Whonix +WIDS +Workspace's +WPA +xaaaabbbbccccdddd +xabcdef +xabcdefabcdefabcd +xddddeeeeffff +xfedcba xkcd XSS +xxxxxx +xyz Yubico Yubikey +Yubikeys +yyyyy Zerouali +zzzzz \ No newline at end of file