|
|
@@ -131,6 +131,51 @@ public class ComponentsTemplateSyntaxPage : PageComponent {
|
|
|
<spry-component name="CodeBlockComponent" sid="component-vala"/>
|
|
|
</section>
|
|
|
|
|
|
+ <section class="doc-section">
|
|
|
+ <h3><code><spry-context></code> - Context Property Preservation</h3>
|
|
|
+ <p>
|
|
|
+ The <code><spry-context></code> tag marks a property to be preserved across
|
|
|
+ action requests. When a component action is triggered, properties marked with this
|
|
|
+ tag are encrypted and included in the action URL, then restored when the action
|
|
|
+ is handled.
|
|
|
+ </p>
|
|
|
+
|
|
|
+ <spry-component name="CodeBlockComponent" sid="context-example"/>
|
|
|
+
|
|
|
+ <h4>How It Works</h4>
|
|
|
+ <ul>
|
|
|
+ <li>Properties marked with <code><spry-context property="name"/></code> are tracked</li>
|
|
|
+ <li>When an action is triggered, these properties are encrypted using <code>CryptographyProvider</code></li>
|
|
|
+ <li>The encrypted context is included in the action URL</li>
|
|
|
+ <li>The server decrypts and restores the properties before calling <code>handle_action()</code></li>
|
|
|
+ </ul>
|
|
|
+
|
|
|
+ <div class="warning-box">
|
|
|
+ <h4>⚠️ Security Warning: Replay Attacks</h4>
|
|
|
+ <p>
|
|
|
+ The encrypted context can be captured and replayed by malicious actors. While the
|
|
|
+ data cannot be tampered with (it's cryptographically signed), an attacker could
|
|
|
+ capture a valid request and replay it later.
|
|
|
+ </p>
|
|
|
+ <ul>
|
|
|
+ <li><strong>Do not</strong> use context for sensitive data that could be exploited if replayed</li>
|
|
|
+ <li><strong>Do not</strong> use context for authentication or authorization decisions</li>
|
|
|
+ <li><strong>Consider</strong> adding timestamps or expiration for time-sensitive operations</li>
|
|
|
+ </ul>
|
|
|
+ <p>
|
|
|
+ <strong>Example attack:</strong> If context contains admin privileges, an attacker
|
|
|
+ could capture a request from an admin session and replay it to gain unauthorized access.
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <h4>Best Practices</h4>
|
|
|
+ <ul>
|
|
|
+ <li>Use context for non-sensitive data like IDs, flags, or UI configuration</li>
|
|
|
+ <li>Validate context data on the server before using it</li>
|
|
|
+ <li>Keep context data minimal - only include what's needed</li>
|
|
|
+ </ul>
|
|
|
+ </section>
|
|
|
+
|
|
|
<section class="doc-section">
|
|
|
<h3><code>spry-res</code> - Static Resources</h3>
|
|
|
<p>
|
|
|
@@ -263,6 +308,18 @@ add_globals_from(header); // Includes header in response for OOB swap""";
|
|
|
header.title = "My App";
|
|
|
}""";
|
|
|
|
|
|
+ // Context example
|
|
|
+ var context_example = get_component_child<CodeBlockComponent>("context-example");
|
|
|
+ context_example.language = "HTML";
|
|
|
+ context_example.code = """<!-- Mark properties to be preserved across actions -->
|
|
|
+<spry-context property="demo_component_name"/>
|
|
|
+<spry-context property="source_file"/>
|
|
|
+
|
|
|
+<div sid="host">
|
|
|
+ <span content-expr="this.demo_component_name">Demo</span>
|
|
|
+ <button spry-action=":ShowSource" spry-target="host">Show Source</button>
|
|
|
+</div>""";
|
|
|
+
|
|
|
// Static resources example
|
|
|
var res_example = get_component_child<CodeBlockComponent>("res-example");
|
|
|
res_example.language = "HTML";
|