{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "8f11c665",
   "metadata": {},
   "source": [
    "# 22-12 · Автоэкранирование Jinja\n",
    "\n",
    "Практика к разделу [«Jinja: шаблоны HTML с данными»](../../site/chapters/glava-22/22-12-jinja-shablony.html)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "43c012a7",
   "metadata": {},
   "source": [
    "## Цель\n",
    "\n",
    "Убедиться, что Jinja экранирует потенциально опасный текст по умолчанию, и увидеть, что делает фильтр |safe."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4586b8b5",
   "metadata": {},
   "source": [
    "## Рабочий пример"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3ea588c1",
   "metadata": {},
   "outputs": [],
   "source": [
    "from flask import Flask, render_template_string\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "opasnyj_tekst = \"<script>alert(1)</script>\"\n",
    "\n",
    "SHABLON = \"<p>{{ tekst }}</p>\"\n",
    "SHABLON_SAFE = \"<p>{{ tekst|safe }}</p>\"\n",
    "\n",
    "\n",
    "@app.route(\"/bez-safe\")\n",
    "def bez_safe():\n",
    "    return render_template_string(SHABLON, tekst=opasnyj_tekst)\n",
    "\n",
    "\n",
    "@app.route(\"/s-safe\")\n",
    "def s_safe():\n",
    "    return render_template_string(SHABLON_SAFE, tekst=opasnyj_tekst)\n",
    "\n",
    "\n",
    "# Оба маршрута зарегистрированы до первого запроса — Flask больше не\n",
    "# позволяет добавлять маршруты после того, как приложение уже ответило\n",
    "# на первый запрос.\n",
    "client = app.test_client()\n",
    "\n",
    "otvet = client.get(\"/bez-safe\")\n",
    "telo = otvet.get_data(as_text=True)\n",
    "print(telo)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b3d8be4c",
   "metadata": {},
   "source": [
    "## Проверка результата"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "721cb013",
   "metadata": {},
   "outputs": [],
   "source": [
    "assert \"<script>alert(1)</script>\" not in telo\n",
    "assert \"&lt;script&gt;\" in telo\n",
    "print(\"Верно: Jinja экранировала тег script — он показан как текст, а не выполнен.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "79f0a99f",
   "metadata": {},
   "source": [
    "## Эксперимент — с |safe разметка проходит как есть"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8fc08df3",
   "metadata": {},
   "outputs": [],
   "source": [
    "otvet2 = client.get(\"/s-safe\")\n",
    "telo2 = otvet2.get_data(as_text=True)\n",
    "\n",
    "assert \"<script>alert(1)</script>\" in telo2\n",
    "print(\"Так и есть: |safe отключает экранирование — поэтому его нельзя применять к вводу, который вы не контролируете.\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Cartesian Python 3.14",
   "language": "python",
   "name": "cartesian-python314"
  },
  "language_info": {
   "name": "python",
   "version": "3.14.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
