内网安全从零开始红队教程，这可能是国内最系统最适合小白的内网安全教程。
# Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com>

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.

from __future__ import annotations

import posixpath
import re

from mkdocs.config.defaults import MkDocsConfig
from mkdocs.structure.files import File, Files
from mkdocs.structure.pages import Page
from re import Match

# -----------------------------------------------------------------------------
# Hooks
# -----------------------------------------------------------------------------

# @todo
def on_page_markdown(
    markdown: str, *, page: Page, config: MkDocsConfig, files: Files
):

    # Replace callback
    def replace(match: Match):
        type, args = match.groups()
        args = args.strip()
        if type == "version":
            if args.startswith("insiders-"):
                return _badge_for_version_insiders(args, page, files)
            else:
                return _badge_for_version(args, page, files)
        elif type == "sponsors":     return _badge_for_sponsors(page, files)
        elif type == "flag":         return flag(args, page, files)
        elif type == "option":       return option(args)
        elif type == "setting":      return setting(args)
        elif type == "feature":      return _badge_for_feature(args, page, files)
        elif type == "plugin":       return _badge_for_plugin(args, page, files)
        elif type == "extension":    return _badge_for_extension(args, page, files)
        elif type == "utility":      return _badge_for_utility(args, page, files)
        elif type == "example":      return _badge_for_example(args, page, files)
        elif type == "default":
            if   args == "none":     return _badge_for_default_none(page, files)
            elif args == "computed": return _badge_for_default_computed(page, files)
            else:                    return _badge_for_default(args, page, files)

        # Otherwise, raise an error
        raise RuntimeError(f"Unknown shortcode: {type}")

    # Find and replace all external asset URLs in current page
    return re.sub(
        r"<!-- md:(\w+)(.*?) -->",
        replace, markdown, flags = re.I | re.M
    )

# -----------------------------------------------------------------------------
# Helper functions
# -----------------------------------------------------------------------------

# Create a flag of a specific type
def flag(args: str, page: Page, files: Files):
    type, *_ = args.split(" ", 1)
    if   type == "experimental":  return _badge_for_experimental(page, files)
    elif type == "required":      return _badge_for_required(page, files)
    elif type == "customization": return _badge_for_customization(page, files)
    elif type == "metadata":      return _badge_for_metadata(page, files)
    elif type == "multiple":      return _badge_for_multiple(page, files)
    raise RuntimeError(f"Unknown type: {type}")

# Create a linkable option
def option(type: str):
    _, *_, name = re.split(r"[.:]", type)
    return f"[`{name}`](#+{type}){{ #+{type} }}\n\n"

# Create a linkable setting - @todo append them to the bottom of the page
def setting(type: str):
    _, *_, name = re.split(r"[.*]", type)
    return f"`{name}` {{ #{type} }}\n\n[{type}]: #{type}\n\n"

# -----------------------------------------------------------------------------

# Resolve path of file relative to given page - the posixpath always includes
# one additional level of `..` which we need to remove
def _resolve_path(path: str, page: Page, files: Files):
    path, anchor, *_ = f"{path}#".split("#")
    path = _resolve(files.get_file_from_path(path), page)
    return "#".join([path, anchor]) if anchor else path

# Resolve path of file relative to given page - the posixpath always includes
# one additional level of `..` which we need to remove
def _resolve(file: File, page: Page):
    path = posixpath.relpath(file.src_uri, page.file.src_uri)
    return posixpath.sep.join(path.split(posixpath.sep)[1:])

# -----------------------------------------------------------------------------

# Create badge
def _badge(icon: str, text: str = "", type: str = ""):
    classes = f"mdx-badge mdx-badge--{type}" if type else "mdx-badge"
    return "".join([
        f"<span class=\"{classes}\">",
        *([f"<span class=\"mdx-badge__icon\">{icon}</span>"] if icon else []),
        *([f"<span class=\"mdx-badge__text\">{text}</span>"] if text else []),
        f"</span>",
    ])

# Create sponsors badge
def _badge_for_sponsors(page: Page, files: Files):
    icon = "material-heart"
    href = _resolve_path("insiders/index.md", page, files)
    return _badge(
        icon = f"[:{icon}:]({href} 'Sponsors only')",
        type = "heart"
    )

# Create badge for version
def _badge_for_version(text: str, page: Page, files: Files):
    spec = text
    path = f"changelog/index.md#{spec}"

    # Return badge
    icon = "material-tag-outline"
    href = _resolve_path("conventions.md#version", page, files)
    return _badge(
        icon = f"[:{icon}:]({href} 'Minimum version')",
        text = f"[{text}]({_resolve_path(path, page, files)})" if spec else ""
    )

# Create badge for version of Insiders
def _badge_for_version_insiders(text: str, page: Page, files: Files):
    spec = text.replace("insiders-", "")
    path = f"insiders/changelog.md#{spec}"

    # Return badge
    icon = "material-tag-heart-outline"
    href = _resolve_path("conventions.md#version-insiders", page, files)
    return _badge(
        icon = f"[:{icon}:]({href} 'Minimum version')",
        text = f"[{text}]({_resolve_path(path, page, files)})" if spec else ""
    )

# Create badge for feature
def _badge_for_feature(text: str, page: Page, files: Files):
    icon = "material-toggle-switch"
    href = _resolve_path("conventions.md#feature", page, files)
    return _badge(
        icon = f"[:{icon}:]({href} 'Optional feature')",
        text = text
    )

# Create badge for plugin
def _badge_for_plugin(text: str, page: Page, files: Files):
    icon = "material-floppy"
    href = _resolve_path("conventions.md#plugin", page, files)
    return _badge(
        icon = f"[:{icon}:]({href} 'Plugin')",
        text = text
    )

# Create badge for extension
def _badge_for_extension(text: str, page: Page, files: Files):
    icon = "material-language-markdown"
    href = _resolve_path("conventions.md#extension", page, files)
    return _badge(
        icon = f"[:{icon}:]({href} 'Markdown extension')",
        text = text
    )

# Create badge for utility
def _badge_for_utility(text: str, page: Page, files: Files):
    icon = "material-package-variant"
    href = _resolve_path("conventions.md#utility", page, files)
    return _badge(
        icon = f"[:{icon}:]({href} 'Third-party utility')",
        text = text
    )

# Create badge for example
def _badge_for_example(text: str, page: Page, files: Files):
    return "\n".join([
        _badge_for_example_download(text, page, files),
        _badge_for_example_view(text, page, files)
    ])

# Create badge for example view
def _badge_for_example_view(text: str, page: Page, files: Files):
    icon = "material-folder-eye"
    href = f"https://mkdocs-material.github.io/examples/{text}/"
    return _badge(
        icon = f"[:{icon}:]({href} 'View example')",
        type = "right"
    )

# Create badge for example download
def _badge_for_example_download(text: str, page: Page, files: Files):
    icon = "material-folder-download"
    href = f"https://mkdocs-material.github.io/examples/{text}.zip"
    return _badge(
        icon = f"[:{icon}:]({href} 'Download example')",
        text = f"[`.zip`]({href})",
        type = "right"
    )

# Create badge for default value
def _badge_for_default(text: str, page: Page, files: Files):
    icon = "material-water"
    href = _resolve_path("conventions.md#default", page, files)
    return _badge(
        icon = f"[:{icon}:]({href} 'Default value')",
        text = text
    )

# Create badge for empty default value
def _badge_for_default_none(page: Page, files: Files):
    icon = "material-water-outline"
    href = _resolve_path("conventions.md#default", page, files)
    return _badge(
        icon = f"[:{icon}:]({href} 'Default value is empty')"
    )

# Create badge for computed default value
def _badge_for_default_computed(page: Page, files: Files):
    icon = "material-water-check"
    href = _resolve_path("conventions.md#default", page, files)
    return _badge(
        icon = f"[:{icon}:]({href} 'Default value is computed')"
    )

# Create badge for metadata property flag
def _badge_for_metadata(page: Page, files: Files):
    icon = "material-list-box-outline"
    href = _resolve_path("conventions.md#metadata", page, files)
    return _badge(
        icon = f"[:{icon}:]({href} 'Metadata property')"
    )

# Create badge for required value flag
def _badge_for_required(page: Page, files: Files):
    icon = "material-alert"
    href = _resolve_path("conventions.md#required", page, files)
    return _badge(
        icon = f"[:{icon}:]({href} 'Required value')"
    )

# Create badge for customization flag
def _badge_for_customization(page: Page, files: Files):
    icon = "material-brush-variant"
    href = _resolve_path("conventions.md#customization", page, files)
    return _badge(
        icon = f"[:{icon}:]({href} 'Customization')"
    )

# Create badge for multiple instance flag
def _badge_for_multiple(page: Page, files: Files):
    icon = "material-inbox-multiple"
    href = _resolve_path("conventions.md#multiple-instances", page, files)
    return _badge(
        icon = f"[:{icon}:]({href} 'Multiple instances')"
    )

# Create badge for experimental flag
def _badge_for_experimental(page: Page, files: Files):
    icon = "material-flask-outline"
    href = _resolve_path("conventions.md#experimental", page, files)
    return _badge(
        icon = f"[:{icon}:]({href} 'Experimental')"
    )

material/overrides/hooks/shortcodes.py
sqlsec/IntranetSecurity
# Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com>

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.

import os
import re

from glob import iglob
from mkdocs.config.defaults import MkDocsConfig
from mkdocs.structure.pages import Page
from urllib.parse import urlencode, urlparse

# -----------------------------------------------------------------------------
# Hooks
# -----------------------------------------------------------------------------

# Determine missing translations and render language overview in the setup
# guide, including links to provide missing translations.
def on_page_markdown(markdown: str, *, page: Page, config: MkDocsConfig, files):
    issue_url = "https://github.com/squidfunk/mkdocs-material/issues/new"
    if page.file.src_uri != "setup/changing-the-language.md":
        return

    # Collect all existing languages
    names: dict[str, str] = {}
    known: dict[str, dict[str, str]] = {}
    for path in iglob("src/templates/partials/languages/*.html"):
        with open(path, "r", encoding = "utf-8") as f:
            data = f.read()

            # Extract language code and name
            name, = re.findall(r"<!-- Translations: (.+) -->", data)
            code, _ = os.path.splitext(os.path.basename(path))

            # Map names and available translations
            names[code] = name
            known[code] = dict(re.findall(
                r"^  \"([^\"]+)\": \"([^\"]*)\"(?:,|$)?", data,
                re.MULTILINE
            ))

            # Remove technical stuff
            for key in [
                "direction",
                "search.config.pipeline",
                "search.config.lang",
                "search.config.separator"
            ]:
                if key in known[code]:
                    del known[code][key]

    # Traverse all languages and compute missing translations
    languages = []
    reference = set(known["en"])
    for code, name in names.items():
        miss = reference - set(known[code])

        # Check each translations
        translations: list[str] = []
        for key, value in known["en"].items():
            if key in known[code]:
                translations.append(
                    f"  \"{key}\": \"{known[code][key]}\""
                )
            else:
                translations.append(
                    f"  \"{key}\": \"{value} ⬅️\""
                )

        # Assemble GitHub issue URL
        link = urlparse(issue_url)
        link = link._replace(query = urlencode({
            "template": "04-add-translations.yml",
            "title": f"Update {name} translations",
            "translations": "\n".join([
                "{% macro t(key) %}{{ {",
                    ",\n".join(translations),
                "}[key] }}{% endmacro %}"
            ]),
            "country-flag": f":flag_{countries[code]}:"
        }))

        # Add translation
        languages.append({
            "flag": countries[code],
            "code": code,
            "name": name,
            "link": link.geturl(),
            "miss": miss
        })

    # Load template and render translations
    env = config.theme.get_env()
    template = env.get_template( "hooks/translations.html")
    translations = template.module.render(
        sorted(languages, key = lambda language: language["name"])
    )

    # Replace translation marker
    return markdown.replace(
        "<!-- hooks/translations.py -->", "\n".join(
            [line.lstrip() for line in translations.split("\n")
        ]
    ))

# -----------------------------------------------------------------------------
# Data
# -----------------------------------------------------------------------------

# Map ISO 639-1 (languages) to ISO 3166 (countries)
countries = dict({
    "af": "za",
    "ar": "ae",
    "be": "by",
    "bg": "bg",
    "bn": "bd",
    "ca": "es",
    "cs": "cz",
    "da": "dk",
    "de": "de",
    "el": "gr",
    "en": "us",
    "eo": "eu",
    "es": "es",
    "et": "ee",
    "eu": "es",
    "fa": "ir",
    "fi": "fi",
    "fr": "fr",
    "gl": "es",
    "he": "il",
    "hi": "in",
    "hr": "hr",
    "hu": "hu",
    "hy": "am",
    "id": "id",
    "is": "is",
    "it": "it",
    "ja": "jp",
    "ka": "ge",
    "kn": "in",
    "ko": "kr",
    "ku-IQ": "iq",
    "lb": "lu",
    "lt": "lt",
    "lv": "lv",
    "mk": "mk",
    "mn": "mn",
    "ms": "my",
    "my": "mm",
    "nb": "no",
    "nl": "nl",
    "nn": "no",
    "pl": "pl",
    "pt-BR": "br",
    "pt": "pt",
    "ro": "ro",
    "ru": "ru",
    "sa": "in",
    "sh": "rs",
    "si": "lk",
    "sk": "sk",
    "sl": "si",
    "sr": "rs",
    "sv": "se",
    "te": "in",
    "th": "th",
    "tl": "ph",
    "tr": "tr",
    "uk": "ua",
    "ur": "pk",
    "uz": "uz",
    "vi": "vn",
    "zh": "cn",
    "zh-Hant": "cn",
    "zh-TW": "tw"
})

material/overrides/hooks/translations.py
sqlsec/IntranetSecurity