The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Mojo::DOM::Role::Restrict - Restrict tags and attributes

VERSION

Version 0.05

SYNOPSIS

        use Mojo::DOM;

        my $html = q|<html><head><script>...</script></head><body><p class="okay" id="allow" onclick="not-allow">Restrict <span class="not-okay">HTML</span></p></body></html>|;

        my $spec = {
                script => 0, # remove all script tags
                '*' => { # apply to all tags
                        '*' => 1, # allow all attributes by default
                        'onclick' => 0 # disable onclick attributes
                },
                span => {
                        class => 0 # disable class attributes on span's
                }
        };

        #<html><head></head><body><p class="okay" id="allow">Restrict <span>HTML</span></p></body></html>
        print Mojo::DOM->with_roles('+Restrict')->new($html, $spec);

        .....

        my $dom = Mojo::DOM->with_roles('+Restrict')->new;

        my $html = q|<html><head><script>...</script></head><body><p class="okay" id="allow" onclick="not-allow">Restrict <span class="not-okay">HTML</span></p></body></html>|;

        my $spec = {
                script => 0, # no script tags
                '*' => { # allow all tags
                        '*' => 1, # allow all attributes
                        onclick => sub { 0 }, # disable onclick attributes
                        id => sub { return @_ }, # enable id attributes
                        class => sub { # allow only 1 class 'okay'
                                my ($attr, $val) = @_;
                                my $match = $val =~ m/^okay$/;
                                return $match ? ($attr, $val) : 0;
                        }
                },
                span => {
                        validate_tag => sub { # replace span tags with b tags
                                return ('b', $_[1]);
                        }
                },
                p => {
                        validate_tag => sub {
                                $_[1]->{id} = "prefixed-" . $_[1]->{id}; # prefix all p tag IDs
                                $_[1]->{'data-unknown'} = 'abc';  # extend all p tags with a data-unknown attribute
                                return @_;
                        }
                },
        };
        
        $dom->parse($html, $spec);
        
        # <html><head></head><body><p class="okay" data-unknown="abc" id="prefixed-allow">Restrict <b>HTML</b></p></body></html>
        $dom->to_string;

        # you can change the spec and then re-render
        $spec = {
                '*' => { # allow all tags
                        '*' => '^not', # where any attr value matches the regex
                },
        };

        $dom->restrict_spec($spec);
        
        # <html><head><script>...</script></head><body><p onclick="not-allow">Restrict <span class="not-okay">HTML</span></p></body></html>
        $dom->to_string;

        # check whether the spec is valid
        $dom->valid; # 0

        # apply spec changess to the Mojo::DOM object
        $dom->restrict;

        # re-check whether the spec is valid
        $dom->valid; # 1

        # render using original render function (Mojo::DOM::HTML::render)
        # <html><head><script>...</script></head><body><p onclick="not-allow">Restrict <span class="not-okay">HTML</span></p></body></html>
        $dom->to_string(1);

        $dom->parse(q|<p class="okay" data-unknown="abc" id="prefixed-allow" onclick="not-allow">Restrict <span class="not-okay">HTML</span></p>|);

        # <p onclick="not-allow">Restrict <span class="not-okay">HTML</span></p>
        $dom->to_string;

SUBROUTINES/METHODS

restrict_spec

Retrieve/Set the specification used to restrict the HTML.

        my $spec = $self->restrict_spec;

        $dom->restrict_spec($spec);

valid

Validate the current DOM against the specification. Returns true(1) if valud returns false(0) if invalid.

        my $html = q|<html><head><script>...</script></head><body><p class="okay" id="allow" onclick="not-allow">Restrict <span class="not-okay">HTML</span></p></body></html>|;

        my $spec = {
                html => 1,
                head => 1,
                script => 1,
                body => 1,
                p => 1,
                span => 1
        };

        my $dom = Mojo::DOM->with_roles('+Restrict')->new($html, $spec); 

        $dom->valid; # 1;

        $spec = {
                html => 1,
                head => 1,
                script => 1,
                body => 1,
                p => 1,
                span => 0
        };

        $dom->valid($spec); # 0;

restrict

Restrict the current DOM against the specification, after calling restrict the specification changes applied become irreversible.

        my $html = q|<html><head><script>...</script></head><body><p class="okay" id="allow" onclick="not-allow">Restrict <span class="not-okay">HTML</span></p></body></html>|;

        my $spec = {
                script => 0, # no script tags
                '*' => { # allow all tags
                        '*' => 1, # allow all attributes
                        onclick => sub { 0 }, # disable onclick attributes
                        id => sub { return @_ }, # enable id attributes
                        class => sub { # allow only 1 class 'okay'
                                my ($attr, $val) = @_;
                                my $match = $val =~ m/^okay$/;
                                return $match ? ($attr, $val) : 0;
                        }
                },
                span => {
                        validate_tag => sub { # replace span tags with b tags
                                return ('b', $_[1]);
                        }
                },
                p => {
                        validate_tag => sub {
                                $_[1]->{id} = "prefixed-" . $_[1]->{id}; # prefix all p tag IDs
                                $_[1]->{'data-unknown'} = 'abc';  # extend all p tags with a data-unknown attribute
                                return @_;
                        }
                },
        };
        
        $dom->parse($html, $spec);

        # render without spec validation
        # <html><head><script>...</script></head><body><p class="okay" id="allow" onclick="not-allow">Restrict <span class="not-okay">HTML</span></p></body></html>
        $dom->to_string(1);
        
        # restrict the DOM
        $dom->restrict;
        
        # render without spec validation
        # <html><head></head><body><p class="okay" data-unknown="abc" id="prefixed-allow">Restrict <b>HTML</b></p></body></html>
        $dom->to_string(1);

diff

Perform a diff comparing the original HTML and the restricted HTML.

        my $html = q|<html>
                <head>
                        <script>...</script>
                </head>
                <body>
                        <p class="okay" id="allow" onclick="not-allow">
                                Restrict
                                <span class="not-okay">HTML</span>
                        </p>
                </body>
        </html>|;

        my $spec = {
                script => 0, # remove all script tags
                '*' => { # apply to all tags
                        '*' => 1, # allow all attributes by default
                        'onclick' => 0 # disable onclick attributes
                },
                span => {
                        class => 0 # disable class attributes on span's
                }
        };

        my $dom = Mojo::DOM->with_roles('+Restrict')->new($html, $spec); 

        #@@ -1,11 +1,11 @@
        # <html>
        #       <head>
        #-              <script>...</script>
        #+              
        #       </head>
        #       <body>
        #-              <p class="okay" id="allow" onclick="not-allow">
        #+              <p class="okay" id="allow">
        #                       Restrict
        #-                      <span class="not-okay">HTML</span>
        #+                      <span>HTML</span>
        #               </p>
        #       </body>
        # </html>
        #\\ No newline at end of file
        my $diff = $dom->diff;

        ....

        $dom->diff($spec, 'Text::Diff', 'diff', { style => 'Unified' });

diff_module

Configure the module used to perform the diff. The default is Text::Diff::diff.

        $dom->diff_module('Text::Diff', 'diff', { style => 'Unified' });

diff_module_name

Get or Set the diff module. The default is Text::Diff.

        $dom->diff_module_name('Text::Diff');

diff_module_method

Get or Set the diff module method. The default is diff.

        $dom->diff_module_method('diff');

diff_module_params

Get or Set the diff module params that are passed as the third argument when calling the diff_module_method. The default is { style => 'Unified' }.

        $dom->diff_module_method({ style => 'Unified' });

diff_module_loaded

Get or Set whether the diff module needs to be loaded. If false the next time the diff method is called on the Mojo::DOM object the module will be required.

        $dom->diff_module_loaded(1|0);

AUTHOR

LNATION, <email at lnation.org>

BUGS

Please report any bugs or feature requests to bug-mojo-dom-role-restrict at rt.cpan.org, or through the web interface at https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Mojo-DOM-Role-Restrict. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc Mojo::DOM::Role::Restrict

You can also look for information at:

ACKNOWLEDGEMENTS

LICENSE AND COPYRIGHT

This software is Copyright (c) 2021 by LNATION.

This is free software, licensed under:

  The Artistic License 2.0 (GPL Compatible)