Skip to content

Commit 03a8a11

Browse files
chibbyalucardWryhder
authored andcommitted
Add support for blockquote alerts in layout files
Signed-off-by: chibbyalucard <[email protected]>
1 parent dc8984a commit 03a8a11

File tree

8 files changed

+241
-35
lines changed

8 files changed

+241
-35
lines changed

README.md

Lines changed: 143 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -122,24 +122,156 @@ icon:
122122
> [!NOTE]
123123
> You can highlight important information in your articles or docs using different types of callouts (also known as admonitions – or alerts, as used in [the Hugo docs](https://gohugo.io/render-hooks/blockquotes/#alerts)).
124124
125-
The examples below use the same syntax as in Github Markdown. The template responsible for rendering them is at `site/layouts/_default/_markup/render-blockquote.html`
125+
For compatibility with both content and layout files, we use a mix of shortcodes and partials to display blockquote alerts. Partials work in layout, but not content files. Shortcodes work in content, but not layout files. Use the partial in layout files, and the shortcode (which internally calls the partial) in content files.
126126

127+
The partial is at `site/layouts/partials/blockquote-alert.html`, and the shortcode is at `site/layouts/shortcodes/blockquote-alert.html`.
128+
129+
There are five available alert types as shown in the examples below:
130+
131+
- note
132+
- tip
133+
- important
134+
- warning
135+
- caution
136+
137+
Omit the `title` parameter to keep the alert type as the default title (for example, a note alert will have "Note" as its title):
138+
139+
```md
140+
<!-- Shortcodes in content files -->
141+
142+
{{< blockquote-alert type="note" title="Optional custom title">}}
143+
Useful information that users should know, even when skimming content.
144+
{{< /blockquote-alert >}}
145+
146+
{{< blockquote-alert type="tip" title="Optional custom title">}}
147+
Helpful advice for doing things better or more easily.
148+
{{< /blockquote-alert >}}
149+
150+
{{< blockquote-alert type="important" title="Optional custom title">}}
151+
Key information users need to know to achieve their goal.
152+
{{< /blockquote-alert >}}
153+
154+
{{< blockquote-alert type="warning" title="Optional custom title">}}
155+
Urgent info that needs immediate user attention to avoid problems.
156+
{{< /blockquote-alert >}}
157+
158+
{{< blockquote-alert type="caution" title="Optional custom title">}}
159+
Advises about risks or negative outcomes.
160+
{{< /blockquote-alert >}}
127161
```
128-
> [!NOTE]
129-
> Useful information that users should know, even when skimming content.
130162

131-
> [!TIP]
132-
> Helpful advice for doing things better or more easily.
163+
In layout files, call the partial directly. Just like shortcode content, anything passed to the `content` parameter is parsed as Markdown. To pass raw HTML instead, use the `html` parameter. Again, the title parameter is optional and will default to the alert type:
133164

134-
> [!IMPORTANT]
135-
> Key information users need to know to achieve their goal.
165+
```html
166+
<!-- Partials in layout files -->
167+
168+
<!-- Anything passed via `content` is interpreted as Markdown -->
169+
170+
{{ partial "blockquote-alert.html" (dict
171+
"type" "note"
172+
"title" "Optional custom title"
173+
"content" "Useful information that users should know, even when skimming content."
174+
) }}
175+
176+
{{ partial "blockquote-alert.html" (dict
177+
"type" "tip"
178+
"title" "Optional custom title"
179+
"content" "Helpful advice for doing things better or more easily."
180+
) }}
181+
182+
{{ partial "blockquote-alert.html" (dict
183+
"type" "important"
184+
"title" "Optional custom title"
185+
"content" "Key information users need to know to achieve their goal."
186+
) }}
187+
188+
{{ partial "blockquote-alert.html" (dict
189+
"type" "warning"
190+
"title" "Optional custom title"
191+
"content" "Urgent info that needs immediate user attention to avoid problems."
192+
) }}
193+
194+
{{ partial "blockquote-alert.html" (dict
195+
"type" "caution"
196+
"title" "Optional custom title"
197+
"content" "Advises about risks or negative outcomes."
198+
) }}
199+
```
200+
201+
In addition to simple string content as shown above, you can also pass in complex nested content with multiple paragraphs and elements:
136202

137-
> [!WARNING]
138-
> Urgent info that needs immediate user attention to avoid problems.
203+
```md
204+
<!-- Shortcode example with more complex content -->
205+
206+
{{< blockquote-alert type="tip" title="Optional custom Title" >}}
207+
This is a tip with **bold text** and _italic_ text.
208+
209+
This is a second paragraph in the same alert.
210+
211+
- List item 1
212+
- List item 2
213+
{{< /blockquote-alert >}}
214+
```
215+
216+
You can do similar in partials. These are all valid options. Additionally, you can assign content to a variable before passing it in, which helps with formatting in longer templates:
217+
218+
```html
219+
<!-- You can wrap your markdown content in backticks if it doesn't itself contain backticks -->
220+
<!-- Note that indented lines could be interpreted as a preformatted code block. -->
221+
{{ $alertContent := `This is a tip with **bold text** and _italic_ text.
222+
223+
This is a second paragraph in the same alert.
224+
225+
- List item 1
226+
- List item 2
227+
`}}
228+
229+
{{ partial "blockquote-alert.html" (dict
230+
"type" "tip"
231+
"title" "Optional custom title"
232+
"content" $alertContent
233+
) }}
234+
235+
<!-- Concatenate multi-line strings (markdown) -->
236+
{{ $alertContent := add
237+
"This is a tip with **bold text** and _italic_ text.\n\n"
238+
"This is a second paragraph in the same alert.\n"
239+
"- List item 1\n"
240+
"- List item 2\n\n"
241+
"`Here's some text in backticks.`"
242+
}}
243+
244+
{{ partial "blockquote-alert.html" (dict
245+
"type" "tip"
246+
"title" "Optional custom title"
247+
"content" $alertContent
248+
) }}
249+
250+
<!-- Pass HTML with nested elements -->
251+
{{ partial "blockquote-alert" (dict
252+
"type" "caution"
253+
"title" "Be Careful!"
254+
"html" "<p>This is a <strong>caution</strong> message.</p><p>It has multiple paragraphs.</p>"
255+
) }}
256+
```
257+
258+
259+
> [!IMPORTANT]
260+
> When working with complex content, make sure to handle line breaks properly within the strings passed to the `content` or `html` parameters. For example, the following will throw a parse error (`html: overlay: parse failed unterminated quoted string in action`):
139261
140-
> [!CAUTION]
141-
> Advises about risks or negative outcomes.
142262
```
263+
{{ partial "blockquote-alert" (dict
264+
"type" "caution"
265+
"title" "Be Careful!"
266+
"html" "<p>This is a <strong>caution</strong> message.</p>
267+
<p>It has multiple paragraphs.</p>"
268+
) }}
269+
```
270+
271+
To avoid this, you can use either of the following options:
272+
273+
- Keep everything on a single line
274+
- Use string concatenation (whether in a variable or directly)
143275

144276
#### Layouts
145277
For controlling what HTML is rendered, you need to work with the site templates. In the directory, `site/layouts/`, you'll find a number of HTML files with various template tags. The first file to check out is `site/layouts/_default/baseof.html` - this is the base layout Hugo uses to build your site that templates extend. Hugo has a lookup order for associating a content entry to a template. A single entry whose type is post (`type: post`), Hugo will look for a layout in `site/layouts/post/single.html`, and if that does not exist, it will fallback to `site/layouts/_default/single.html`.

site/content/blog/2025-04-02-zap-updates-march-2025/index.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ authors:
1515

1616
## Highlights
1717

18-
> [!IMPORTANT]
19-
> The big news last month was the release of [2.16.1](/blog/2025-03-25-zap-2-16-1/)!
18+
{{< blockquote-alert type="important">}}
19+
The big news last month was the release of [2.16.1](/blog/2025-03-25-zap-2-16-1/)!
20+
{{< /blockquote-alert >}}
2021

2122
As part of this release the [Script Console](/docs/desktop/addons/script-console/) now uses the main
2223
[Output](/docs/desktop/ui/tabs/output/) tab instead of its own "Script Output" panel.
@@ -45,8 +46,9 @@ The following significant changes have been made to this website:
4546
* A new [Script Security](/docs/getting-further/script-security/) advanced guide
4647
* Even more [Authentication Tests](/docs/scans/auth/)
4748

48-
> [!NOTE]
49-
> We now have the option to highlight important information, as demonstrated here!
49+
{{< blockquote-alert type="note">}}
50+
We now have the option to highlight important information, as demonstrated here!
51+
{{< /blockquote-alert >}}
5052

5153
## GitHub Pulse
5254
Here are some statistics for the two main ZAP repositories:

site/content/blog/2025-04-09-portswigger-labs-broken-brute-force-protection-ip-block/index.md

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,13 @@ Copy-paste the lab URL into the *URL to explore* field and launch your browser w
6161

6262
![launch-test-site-ZAP-configured-browser.png](images/launch-test-site-ZAP-configured-browser.png)
6363

64-
> [!NOTE]
65-
> If you have any issues launching your browser from ZAP, see the following pages for help. ZAP uses add-ons to enhance its core features, including ones which provide webdrivers for interfacing with supported browsers. These are installed by default and expose some configurable options:
66-
>
67-
> 1. [How can I fix 'browser was not found'?](/faq/how-can-i-fix-browser-was-not-found/) - ZAP Docs (FAQ)
68-
> 2. [Manual Explore](/docs/desktop/addons/quick-start/#manual-explore) - ZAP Docs
69-
> 3. [Selenium](/docs/desktop/addons/selenium/) - ZAP Docs
64+
{{< blockquote-alert type="note">}}
65+
If you have any issues launching your browser from ZAP, see the following pages for help. ZAP uses add-ons to enhance its core features, including ones which provide webdrivers for interfacing with supported browsers. These are installed by default and expose some configurable options:
66+
67+
1. [How can I fix 'browser was not found'?](/faq/how-can-i-fix-browser-was-not-found/) - ZAP Docs (FAQ)
68+
2. [Manual Explore](/docs/desktop/addons/quick-start/#manual-explore) - ZAP Docs
69+
3. [Selenium](/docs/desktop/addons/selenium/) - ZAP Docs
70+
{{< /blockquote-alert >}}
7071

7172
Assuming you’ve opened the lab in a browser configured to proxy through ZAP, let’s try to log in with a random password. We want to capture a POST request we can work with in ZAP. I’ll try “randompass”. We’re notified that this is an “Incorrect password”, which is expected:
7273

@@ -96,8 +97,9 @@ After one minute, we can indeed make more login attempts. The idea is that if we
9697

9798
If we enter our own credentials, `wiener:peter`, on every third login attempt, the IP block never activates. Each successful login resets the counter tracking the number of failed login attempts. We can keep going until we’ve tried enough passwords from our wordlist to find the right one for Carlos' account.
9899

99-
> [!NOTE]
100-
> This bypass — taking advantage of a logic flaw to reset the failure counter — enables us to brute-force Carlos’ password and successfully solve this lab. Although not the point of the lab, we can also wait out the IP block since we’re dealing with only a few credentials. This is covered in “Method 2: Wait Out the IP Block”.
100+
{{< blockquote-alert type="note">}}
101+
This bypass — taking advantage of a logic flaw to reset the failure counter — enables us to brute-force Carlos’ password and successfully solve this lab. Although not the point of the lab, we can also wait out the IP block since we’re dealing with only a few credentials. This is covered in “Method 2: Wait Out the IP Block”.
102+
{{< /blockquote-alert >}}
101103

102104
What about changing our IP address? I used the [`X-Forwarded-For`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For) header successfully in another lab. But the server here appears to block IPs based on the client's actual IP address (determined by the network layer rather than HTTP headers from the application layer), which makes sense in the context of rate-limiting. Rotating IP addresses via a proxy or VPN could work, but we won’t explore that here.
103105

@@ -564,8 +566,9 @@ All functions, except the `log` function, are part of a required interface that
564566

565567
![implementation-error.png](images/implementation-error.png)
566568

567-
> [!NOTE]
568-
> Refer to the default templates for the interfaces required for each script type. You can find these in the Templates section of the Scripts tab. They include documentation comments describing each function and its parameters. You can also create new scripts from the templates.
569+
{{< blockquote-alert type="note">}}
570+
Refer to the default templates for the interfaces required for each script type. You can find these in the Templates section of the Scripts tab. They include documentation comments describing each function and its parameters. You can also create new scripts from the templates.
571+
{{< /blockquote-alert >}}
569572

570573
You can save the file now. Also, check that the script is enabled, as disabled scripts won’t be available for selection when needed. If you missed the *Enable* checkbox earlier, you can right-click the filename in the *Scripts* tab and select *Enable Script(s)*.
571574

@@ -583,10 +586,11 @@ After you open the *Add Payload* dialog, you can add the Payload Generator scrip
583586

584587
Save the payload and return to the main Fuzzer dialog. Then, run the Fuzzer with *Start Fuzzer*.
585588

586-
> [!IMPORTANT]
587-
> You might notice that even though the payloads are generated correctly (as the logs in the script output panel show), the requests are sent in the wrong order. This causes an unexpected IP block early on. As a result, most of the requests are rejected with the message: `You have made too many incorrect login attempts. Please try again in 1 minute(s).`
588-
>
589-
> This is due to the Fuzzer’s concurrency settings. You can enable sequential execution by setting the number of execution threads to 1. However, this slows down the Fuzzer a great deal. An alternative is to throttle requests with a small delay of 100–200 milliseconds. See [Options Fuzzer screen](/docs/desktop/addons/fuzzer/options/) for more detail.
589+
{{< blockquote-alert type="important">}}
590+
You might notice that even though the payloads are generated correctly (as the logs in the script output panel show), the requests are sent in the wrong order. This causes an unexpected IP block early on. As a result, most of the requests are rejected with the message: `You have made too many incorrect login attempts. Please try again in 1 minute(s).`
591+
592+
This is due to the Fuzzer’s concurrency settings. You can enable sequential execution by setting the number of execution threads to 1. However, this slows down the Fuzzer a great deal. An alternative is to throttle requests with a small delay of 100–200 milliseconds. See [Options Fuzzer screen](/docs/desktop/addons/fuzzer/options/) for more detail.
593+
{{< /blockquote-alert >}}
590594

591595
You can skip over the next section and head to [Have Username, Got Password](#have-username-got-password).
592596

@@ -715,8 +719,9 @@ You can optionally move the script to the top of the processor list. Then, run t
715719

716720
Once the Fuzzer is done, we can inspect the results. We’re looking for indications of a successful login. So, we’ll sort the results in descending order using the status code column (simply “*Code”* in the UI).
717721

718-
> [!NOTE]
719-
> Both of these solutions are valid. As you might have noticed if you’ve solved a lab more than once, different lab instances can have different password solutions. So, you could see different passwords than shown below.
722+
{{< blockquote-alert type="note">}}
723+
Both of these solutions are valid. As you might have noticed if you’ve solved a lab more than once, different lab instances can have different password solutions. So, you could see different passwords than shown below.
724+
{{< /blockquote-alert >}}
720725

721726
### Method 1: Interleave Wordlists With Valid Credentials
722727

site/content/docs/getting-further/script-security.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ For more details on ZAP’s security posture see the
2222
### Script Capabilities
2323
As noted on the [Script Console](/docs/desktop/addons/script-console/) page:
2424

25-
> [!WARNING]
26-
> Scripts run with the same permissions as ZAP, so do not run any scripts that you do not trust!
25+
{{< blockquote-alert type="warning">}}
26+
Scripts run with the same permissions as ZAP, so do not run any scripts that you do not trust!
27+
{{< /blockquote-alert >}}
2728

2829
All scripts can call other scripts and any command line tools that are accessible to them based on OS permissions.
2930
Scripts can access any online services unless restricted by firewalls or similar.

site/content/faq/somethings-not-working-what-should-i-do.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,6 @@ You can chat with the ZAP team on [Slack](/slack/), if you have not already join
6363
You can raise issues (bugs or new features) at the [issue
6464
tracker](https://github.com/zaproxy/zaproxy/issues/new/choose).
6565

66-
> [!WARNING]
67-
> Please do not ask questions as issues - they will be closed and you will be redirected to the [ZAP user group](https://groups.google.com/group/zaproxy-users).
66+
{{< blockquote-alert type="warning">}}
67+
Please do not ask questions as issues - they will be closed and you will be redirected to the [ZAP user group](https://groups.google.com/group/zaproxy-users).
68+
{{< /blockquote-alert >}}

site/layouts/page/download.html

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,19 @@ <h2 id="main">{{ .title }}</h2>
7575
Next to it, if you trust the downloaded installer, you can click <strong>Open anyway</strong>.
7676
</div>
7777
</blockquote>
78+
79+
80+
81+
82+
83+
84+
85+
{{ partial "blockquote-alert.html" (dict
86+
"type" "warning"
87+
"html" "<p>This is a <strong>caution</strong> message.</p><p>It has multiple paragraphs.</p>"
88+
) }}
89+
90+
7891
</div>
7992
</section>
8093

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{{ $emojis := dict
2+
"caution" ":bangbang:"
3+
"important" ":information_source:"
4+
"note" ":memo:"
5+
"tip" ":bulb:"
6+
"warning" ":warning:"
7+
}}
8+
9+
{{ $type := .type | default "note" }}
10+
{{ $title := .title | default "" }}
11+
{{ $content := .content | default "" }}
12+
{{ $html := .html | default "" }}
13+
14+
{{/* Handle inner content from shortcodes */}}
15+
{{ if .inner }}
16+
{{ $content = .inner }}
17+
{{ end }}
18+
19+
{{ if $type }}
20+
<blockquote class="alert alert-{{ $type }}">
21+
<p class="alert-heading">
22+
{{ transform.Emojify (index $emojis $type) }}
23+
{{ if $title }}
24+
{{ $title }}
25+
{{ else }}
26+
{{ or (i18n $type) (title $type) }}
27+
{{ end }}
28+
</p>
29+
<div class="alert-content">
30+
{{ if $html }}
31+
{{ $html | safeHTML }}
32+
{{ else if $content }}
33+
{{ $content | markdownify }}
34+
{{ else }}
35+
{{ i18n "no-content" }}
36+
{{ end }}
37+
</div>
38+
</blockquote>
39+
{{ else }}
40+
<blockquote>
41+
{{ $content | markdownify }}
42+
</blockquote>
43+
{{ end }}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{{ $type := .Get "type" | default "note" }}
2+
{{ $title := .Get "title" | default "" }}
3+
{{ $inner := .Inner }}
4+
5+
{{ partial "blockquote-alert" (dict
6+
"type" $type
7+
"title" $title
8+
"inner" $inner
9+
) }}

0 commit comments

Comments
 (0)