Модуль misaka
- это привязка на основе CFFI
для библиотеки Hoedown
, написанной на языке C. В ней есть быстрое средство визуализации HTML и функциональность для создания настраиваемых средств визуализации (например, страниц руководства или LaTeX).
misaka
в виртуальное окружение:# создаем виртуальное окружение, если нет $ python3 -m venv .venv --prompt VirtualEnv # активируем виртуальное окружение $ source .venv/bin/activate # ставим модуль misaka (VirtualEnv) Idea@Centre:~$ python -m pip install -U misaka
Модуль misaka
тестировался на CPython 3.3, 3.4, 3.5, 3.6, 3.8 и PyPy 3.7.
misaka
;misaka
;misaka
;misaka
.Внимание! Некоторые встроенные в модуль misaka
расширения, поддерживают не всю функциональность, описанную в одноименных расширениях модуля Python-Мarkdown
.
Название | Константа |
tables | EXT_TABLES |
fenced-code | EXT_FENCED_CODE |
footnotes | EXT_FOOTNOTES |
autolink | EXT_AUTOLINK |
strikethrough | EXT_STRIKETHROUGH |
underline | EXT_UNDERLINE |
highlight | EXT_HIGHLIGHT |
quote | EXT_QUOTE |
superscript | EXT_SUPERSCRIPT |
math | EXT_MATH |
no-intra-emphasis | EXT_NO_INTRA_EMPHASIS |
space-headers | EXT_SPACE_HEADERS |
math-explicit | EXT_MATH_EXPLICIT |
disable-indented-code | EXT_DISABLE_INDENTED_CODE |
Название | Константа |
skip-html | HTML_SKIP_HTML |
escape | HTML_ESCAPE |
hard-wrap | HTML_HARD_WRAP |
use-xhtml | HTML_USE_XHTML |
misaka
misaka.html(text, extensions=0, render_flags=0)
:Метод misaka.html()
преобразует текст Markdown в HTML.
Аргумент extensions
может быть списком или кортежем расширений, например ('fenced-code', 'footnotes', 'strikethrough')
или целое число (константа), например EXT_FENCED_CODE | EXT_FOOTNOTES | EXT_STRIKETHROUGH
.
Аргумент render_flags
может быть списком или кортежем флагов, например ('skip-html', 'hard-wrap')
или целое число (константа), например HTML_SKIP_HTML | HTML_HARD_WRAP
.
misaka.smartypants(text)
:Метод misaka.smartypants()
преобразует последовательности символов в HTML-сущности.
Markdown | HTML |
's (s, t, m, d, re, ll, ve) | ’s |
"Quotes" | “Quotes” |
--- | — |
-- | – |
... | … |
. . . | … |
(c) | © |
(r) | ® |
(tm) | ™ |
3/4 | ¾ |
1/2 | ½ |
1/4 | ¼ |
misaka.escape_html(text, escape_slash=False)
:Метод misaka.escape_html()
привязка для функции экранирования HTML Hoedown
.
Реализация основана на рекомендациях OWASP XSS Prevention:
&
--> &
<
--> <
>
--> >
"
--> "
'
--> '
;/
--> /
когда аргумент escape_slash=True
misaka
.misaka.Markdown(renderer, extensions=0)
:Класс misaka.Markdown()
разбирает разметку документа Мarkdown и отображает его с помощью данного средства визуализации.
Аргумент extensions
может быть списком или кортежем расширений, например ('fenced-code', 'footnotes', 'strikethrough')
или целое число (константа), например EXT_FENCED_CODE | EXT_FOOTNOTES | EXT_STRIKETHROUGH
.
Аргумент renderer
это экземпляр класса HtmlRenderer()
.
misaka.HtmlRenderer(flags=0, nesting_level=0)
:Класс misaka.HtmlRenderer()
представляет собой обертку для средства визуализации HTML, включенного в Hoedown
.
Аргумент flags
может быть списком или кортежем флагов, например ('skip-html', 'hard-wrap')
или целое число (константа), например HTML_SKIP_HTML | HTML_HARD_WRAP
.
Аргумент nesting_level
ограничивает то, что включено в оглавление. Значение по умолчанию - 0, заголовков нет.
Экземпляр HtmlRenderer()
нельзя использовать совместно с несколькими экземплярами Markdown
, поскольку он содержит состояние, измененное экземпляром Markdown
.
misaka.SaferHtmlRenderer(flags=(), sanitization_mode='skip-html', nesting_level=0, link_rewrite=None, img_src_rewrite=None)
:Класс misaka.SaferHtmlRenderer()
представляет собой подкласс HtmlRenderer
, который добавляет защиту от межсайтового скриптинга (XSS
):
Флаг skip-html
включен по умолчанию, предотвращая внедрение HTML-элементов. Если необходимо оставить HTML-код вместо его полного удаления, измените на sanitization_mode=escape
.
URL-адреса ссылок и изображений фильтруются, чтобы предотвратить внедрение JavaScript. Это также блокирует преобразование адресов электронной почты в ссылки. Смотрите метод check_url() ниже.
При желании URL-адреса также могут быть переписаны для противодействия другим атакам, например фишингу.
Для включения перезаписи URL требуются дополнительные аргументы:
Параметры:
link_rewrite
- URL страницы редиректа, необходим для перезаписи атрибута ссылки href
; img_src_rewrite
- URL-адрес прокси изображения, необходимый для перезаписи атрибута изображения src
.Обе строки должны включать заполнитель {url}
для цели с кодировкой URL. Примеры:
link_rewrite='https://example.com/redirect?url={url}', img_src_rewrite='https://img-proxy-domain/{url}'
SaferHtmlRenderer
:autolink(raw_url, is_email)
- фильтрует ссылки, созданные расширением autolink
.
check_url(url, is_image_src=False)
- этот метод используется для проверки URL. Возвращает True
, если URL является безопасным, в противном случае - False
.
Реализация по умолчанию разрешает только ссылки HTTP и HTTPS. Это означает, что не будут обрабатываться mailto:
, xmpp:
, ftp:
и т. д.
Этот метод существует специально для того, чтобы упростить настройку фильтрации ссылок через подклассы, поэтому не стесняйтесь писать свои собственные.
Если думаете о внедрении подхода с использованием черного списка, прочтите о том какие схемы URL-адресов опасны (можно использовать XSS)?.
image(raw_url, title='', alt='')
- фильтрует атрибут src
изображения.
Обратите внимание, что фильтрация исходного URL-адреса тега <img>
- это только самая базовая защита и в большинстве случаев бесполезна в современных браузерах (по умолчанию они блокируют JavaScript). Примером атаки, которую не предотвращает фильтрация, является фишинг на основе HTTP-аутентификации.
Чтобы смягчить эту проблему, необходимо разрешать изображения только из доверенных источников, например вашего собственного хранилища изображений или прокси (смотрите метод .rewrite_url()
).
link(content, raw_url, title='')
- фильтрует ссылки.
rewrite_url(url, is_image_src=False)
- этот метод вызывается для перезаписи URL-адресов.
Он использует self.link_rewrite
или self.img_src_rewrite
в зависимости от значения is_image_src
. URL-адрес возвращается без изменений, если соответствующий атрибут равен None
.
misaka.HtmlTocRenderer(nesting_level=6)
:Метод misaka.HtmlTocRenderer()
представляет собой обертку для средства визуализации Оглавления, включенного в Hoedown
.
Аргумент nesting_level
ограничивает то, что включается в оглавление. Значение по умолчанию - 6, все заголовки.
Экземпляр HtmlTocRenderer
нельзя использовать совместно с несколькими экземплярами Markdown
, поскольку он несет состояние, измененное экземпляром Markdown
.
misaka.BaseRenderer
:Класс misaka.BaseRenderer
определяет следующие атрибуты и методы:
blockcode(text, lang='')
, аргумент lang
содержит язык по умолчанию, если включено расширение изолированные блоки кода, а язык определен в блоке кода.
blockquote(content)
;
header(content, level)
- уровень, может быть числом от 1 до 6.
hrule()
;
list(content, is_ordered, is_block)
;
listitem(content, is_ordered, is_block)
;
paragraph(content)
;
table(content) - зависит от расширения
tables`.
table_header(content)
- зависит от расширения tables
.
table_body(content)
- зависит от расширения tables
.
table_row(content)
- зависит от расширения tables
.
table_cell(content, align, is_header)
- зависит от расширения tables
, аргумент align
может быть пустым, center
, left
или right
.
footnotes(content)
- зависит от расширения footnotes
.
footnote_def(content, num)
- зависит от расширения footnotes
.
footnote_ref(num)
- зависит от расширения footnotes
.
blockhtml(text)
;
autolink(link, is_email)
- зависит от расширения autolink
.
codespan(text)
;
double_emphasis(content)
;
emphasis(content)
;
underline(content)
- Depends on the underline extension.
highlight(content) - зависит от расширения
highlight`.
quote(content) - зависит от расширения
quote`.
image(link, title='', alt='')
;
linebreak()
;
link(content, link, title='')
;
triple_emphasis(content)
;
strikethrough(content)
- зависит от расширения strikethrough
.
superscript(content)
- зависит от расширения superscript
.
math(text, displaymode)
- зависит от расширения math
. Аргумент displaymode
может быть 0 или 1. HtmlRenderer
обрабатывает это следующим образом:
if displaymode == 1: return f'\\[{text}\\]' else: # displaymode == 0 return f'\\({text}\\)'
raw_html(text)
;
entity(text)
;
normal_text(text)
;
doc_header(inline_render)
;
doc_footer(inline_render)
.
misaka
:Очень простой пример:
import misaka text = """ # Some text * list * list * list ### Some other text """ html = misaka.html(text) print(html) # <h1>Some text</h1> # <ul> # <li>list</li> # <li>list</li> # <li>list</li> # </ul> # <h3>Some other text</h3>
или
>>> from misaka import Markdown, HtmlRenderer text = """ Here is some code: ```python print(123) ``` More code: print(123) """ >>> render = HtmlRenderer() >>> md = Markdown(render) >>> html = md(text) >>> print(html) # <p>Here is some code:</p> # <p><code>python # print(123) # </code></p> # <p>More code:</p> # <pre><code>print(123) # </code></pre>
misaka
.Вот простой пример, который использует модуль pygments
для подсветки кода. Для воспроизведения этого примера модуль pygments
должен быть так же установлены в виртуальном окружении.
Приведенный ниже код содержит подклассы HtmlRenderer
и реализует метод BaseRenderer.blockcode()
.
import misaka as m from pygments import highlight from pygments.formatters import HtmlFormatter, ClassNotFound from pygments.lexers import get_lexer_by_name class HighlighterRenderer(m.HtmlRenderer): def blockcode(self, text, lang): try: lexer = get_lexer_by_name(lang, stripall=True) except ClassNotFound: lexer = None if lexer: formatter = HtmlFormatter() return highlight(text, lexer, formatter) # default t = m.escape_html(text.strip()) return f'\n<pre><code>{t}</code></pre>\n' renderer = HighlighterRenderer() md = m.Markdown(renderer, extensions=('fenced-code',)) text = """ Here is some code: ```python print(123) ``` More code: print(123) """ html = md(text) print(html) # <p>Here is some code:</p> # <div class="highlight"><pre><span></span> # <span class="nb">print</span><span class="p">(</span> # <span class="mi">123</span><span class="p">)</span> # </pre></div> # <p>More code:</p> # <pre><code>print(123)</code></pre>