diff --git a/README.md b/README.md index 8eece1c..a989d96 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,59 @@ # Nihilist OPSEC blog -mkdocs-material markdown edition -# How to run +## Work on blog posts -## Docker +If you're here and want to contribute to our blog posts, you only need to clone the [opsec-blogposts](http://git.nowherejezfoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion/nihilist/opsec-blogposts) repo. -To run the blog yourself, you'll need a Tor daemon running with socks5 proxy at `localhost:9050`. It will be used to clone/pull the repository from Docker container. - -You also need an onionv3 domain and hidden service exposing `localhost:7080`as HTTP. - -Download 3 files from the `deploy/` directory. You only need to edit the `SITE_URL` in `docker-compose.yml` to the vanity domain you generated. - -Then run: ``` -$ docker compose up -d && docker compose logs -f +$ git -c "http.proxy=socks5h://127.0.0.1:9050" clone "http://git.nowherejezfoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion/nihilist/opsec-blogposts.git" --depth=1 ``` -It will automatically clone the repository and start serving it with nginx on the URL you provided. -## Local development +We have a [contributing guide](http://blog.nowherejezfoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion/opsec/contribute/) that will help you with later steps. It may be somewhat incomplete currently so I'll list some general steps you should consider while writing/editing markdown blog posts. + +- the main file of each post's directory is `index.md`, you should also make references to `index.md` of other blog posts + for example: `Do it like [we did before](../anonsms/index.md).` +- you should fill the metatags with necessary information about author and blog post in general: + ``` + --- + author: oxeo0 + date: 2025-05-16 + gitea_url: "http://git.nowherejezfoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion/nihilist/blog-contributions/issues/278" + xmr: 862Sp3N5Y8NByFmPVLTPrJYzwdiiVxkhQgAdt65mpYKJLdVDHyYQ8swLgnVr8D3jKphDUcWUCVK1vZv9u8cvtRJCUBFb8MQ + --- + + # Blog post title + ``` +- you can preview markdown in VSCodium or other markdown editors. If you need to see how it would look on our blog, check the *Run the blog locally* section below. +- it's preferred to compress larger (>30kB) images to `AVIF` format using the [avifenc](https://manpages.debian.org/unstable/libavif-bin/avifenc.1.en.html) command: + ``` + $ avifenc 0.png --yuv 420 --range l -q 50 -c svt --speed 0 --ignore-exif -o 0.png + ``` + We'll handle that if you're unsure or face any problems with compression. +- Even though all issues should remain [on the main repository](http://git.nowherejezfoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion/nihilist/blog-contributions), you should make Pull Request to the [opsec-blogposts](http://git.nowherejezfoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion/nihilist/opsec-blogposts) repo once you're done with your contribution. + +## Clone everything + +Our blog consists of a few git submodules. To fully clone it, use the following command: +``` +$ git -c "http.proxy=socks5h://127.0.0.1:9050" clone "http://git.nowherejezfoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion/nihilist/blog-contributions.git" --depth=1 --recursive --shallow-submodules +``` + +In case of `connection refused` error, make sure you have Tor daemon running in the background listening with `SocksPort 9050`. + +The cloning process over the Tor network can take a while. Please be patient and try again in case of network issues. + +We try to optimize the size of this repository and its submodules, currently those are: +``` +26.31M blog-contributions +36.48M hacking +44.84M opsec +6.78M productivity +33.10M selfhosting + +147.5M total +``` + +## Run the blog locally You need to install [mkdocs-material package](https://pkgs.org/search/?q=mkdocs-material) from your distro's repository or [from pip](https://squidfunk.github.io/mkdocs-material/getting-started/). @@ -28,3 +64,7 @@ $ mkdocs serve It should be served on `http://locahost:8000` +## Run the blog on the server + +We have a [separate repo](http://git.nowherejezfoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion/nihilist/blog-deploy) to run the blog post in **production environment** - with automatic updates and reverse proxy. + diff --git a/scripts/find_unused_images.py b/scripts/find_unused_images.py new file mode 100644 index 0000000..ef620f3 --- /dev/null +++ b/scripts/find_unused_images.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +import os +import re +import argparse + +def get_all_images(images_dir): + allowed_ext = {'.png', '.jpeg', '.jpg', '.webp', '.gif'} + image_files = set() + + for root, _, files in os.walk(images_dir): + for filename in files: + ext = os.path.splitext(filename)[1].lower() # use lower-case + if ext in allowed_ext: + pth = os.path.abspath(os.path.join(root, filename)) + image_files.add(pth) + return image_files + +def get_markdown_image_references(posts_dir): + image_refs = set() + # regex matches: ![optional alt text](path) + pattern = re.compile(r'!\[.*?\]\((.*?)\)') + + for root, _, files in os.walk(posts_dir): + for filename in files: + if filename.endswith('.md'): + file_path = os.path.join(root, filename) + try: + with open(file_path, 'r', encoding='utf-8') as f: + content = f.read() + except: + continue + matches = pattern.findall(content) + for match in matches: + ref = match.strip().strip('"').strip("'") + refreal = os.path.join(root, ref) + #print(refreal, ref, os.path.abspath(refreal)) + image_refs.add(os.path.abspath(refreal)) + return image_refs + +def main(): + parser = argparse.ArgumentParser( + description="Find unused images (png, jpeg, jpg) that are not referenced by any Markdown post." + ) + parser.add_argument("--docs", required=True, + help="main docs/ directory.") + args = parser.parse_args() + + all_images = get_all_images(args.docs) + + image_references = get_markdown_image_references(args.docs) + unused_images = all_images - image_references + + if unused_images: + print("Unused images:") + size_cum = 0 + for img in sorted(unused_images): + size_cum += os.path.getsize(img) + print(os.path.relpath(img, start=os.path.abspath(args.docs))) + print(f'\nPossible savings: {round(size_cum/1024)} kB') + else: + print("No unused images found.") + +if __name__ == "__main__": + main()