1# --
2# Copyright (C) 2001-2020 OTRS AG, https://otrs.com/
3# --
4# This software comes with ABSOLUTELY NO WARRANTY. For details, see
5# the enclosed file COPYING for license information (GPL). If you
6# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
7# --
8
9package Kernel::System::Web::InterfacePublic;
10
11use strict;
12use warnings;
13
14use Kernel::Language qw(Translatable);
15
16our @ObjectDependencies = (
17    'Kernel::Config',
18    'Kernel::Output::HTML::Layout',
19    'Kernel::System::DB',
20    'Kernel::System::Log',
21    'Kernel::System::Main',
22    'Kernel::System::Web::Request',
23);
24
25=head1 NAME
26
27Kernel::System::Web::InterfacePublic - the public web interface
28
29=head1 DESCRIPTION
30
31the global public web interface
32
33=head1 PUBLIC INTERFACE
34
35=head2 new()
36
37create public web interface object
38
39    use Kernel::System::Web::InterfacePublic;
40
41    my $Debug = 0;
42    my $Interface = Kernel::System::Web::InterfacePublic->new(
43        Debug      => $Debug,
44        WebRequest => CGI::Fast->new(), # optional, e. g. if fast cgi is used, the CGI object is already provided
45    );
46
47=cut
48
49sub new {
50    my ( $Type, %Param ) = @_;
51
52    # allocate new hash for object
53    my $Self = {};
54    bless( $Self, $Type );
55
56    # get debug level
57    $Self->{Debug} = $Param{Debug} || 0;
58
59    # performance log
60    $Self->{PerformanceLogStart} = time();
61
62    $Kernel::OM->ObjectParamAdd(
63        'Kernel::System::Log' => {
64            LogPrefix => $Kernel::OM->Get('Kernel::Config')->Get('CGILogPrefix'),
65        },
66        'Kernel::System::Web::Request' => {
67            WebRequest => $Param{WebRequest} || 0,
68        },
69    );
70
71    # debug info
72    if ( $Self->{Debug} ) {
73        $Kernel::OM->Get('Kernel::System::Log')->Log(
74            Priority => 'debug',
75            Message  => 'Global handle started...',
76        );
77    }
78
79    return $Self;
80}
81
82=head2 Run()
83
84execute the object
85
86    $Interface->Run();
87
88=cut
89
90sub Run {
91    my $Self = shift;
92
93    my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
94
95    my $QueryString = $ENV{QUERY_STRING} || '';
96
97    # Check if https forcing is active, and redirect if needed.
98    if ( $ConfigObject->Get('HTTPSForceRedirect') ) {
99
100        # Some web servers do not set HTTPS environment variable, so it's not possible to easily know if we are using
101        #   https protocol. Look also for similarly named keys in environment hash, since this should prevent loops in
102        #   certain cases.
103        if (
104            (
105                !defined $ENV{HTTPS}
106                && !grep {/^HTTPS(?:_|$)/} keys %ENV
107            )
108            || $ENV{HTTPS} ne 'on'
109            )
110        {
111            my $Host = $ENV{HTTP_HOST} || $ConfigObject->Get('FQDN');
112
113            # Redirect with 301 code. Add two new lines at the end, so HTTP headers are validated correctly.
114            print "Status: 301 Moved Permanently\nLocation: https://$Host$ENV{REQUEST_URI}\n\n";
115            return;
116        }
117    }
118
119    my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
120
121    my %Param;
122
123    # get session id
124    $Param{SessionName} = $ConfigObject->Get('CustomerPanelSessionName')         || 'CSID';
125    $Param{SessionID}   = $ParamObject->GetParam( Param => $Param{SessionName} ) || '';
126
127    # drop old session id (if exists)
128    $QueryString =~ s/(\?|&|;|)$Param{SessionName}(=&|=;|=.+?&|=.+?$)/;/g;
129
130    # define framework params
131    my $FrameworkParams = {
132        Lang         => '',
133        Action       => '',
134        Subaction    => '',
135        RequestedURL => $QueryString,
136    };
137    for my $Key ( sort keys %{$FrameworkParams} ) {
138        $Param{$Key} = $ParamObject->GetParam( Param => $Key )
139            || $FrameworkParams->{$Key};
140    }
141
142    # validate language
143    if ( $Param{Lang} && $Param{Lang} !~ m{\A[a-z]{2}(?:_[A-Z]{2})?\z}xms ) {
144        delete $Param{Lang};
145    }
146
147    # Check if the browser sends the SessionID cookie and set the SessionID-cookie
148    # as SessionID! GET or POST SessionID have the lowest priority.
149    if ( $ConfigObject->Get('SessionUseCookie') ) {
150        $Param{SessionIDCookie} = $ParamObject->GetCookie( Key => $Param{SessionName} );
151        if ( $Param{SessionIDCookie} ) {
152            $Param{SessionID} = $Param{SessionIDCookie};
153        }
154    }
155
156    # get common application and add-on application params
157    # Important!
158    # This must be done before creating the layout object,
159    # because otherwise the action parameter is not passed and then
160    # the loader can not load module specific JavaScript and CSS
161    # For details see bug: http://bugs.otrs.org/show_bug.cgi?id=6471
162    my %CommonObjectParam = %{ $ConfigObject->Get('PublicFrontend::CommonParam') };
163    for my $Key ( sort keys %CommonObjectParam ) {
164        $Param{$Key} = $ParamObject->GetParam( Param => $Key ) || $CommonObjectParam{$Key};
165    }
166
167    # security check Action Param (replace non-word chars)
168    $Param{Action} =~ s/\W//g;
169
170    $Kernel::OM->ObjectParamAdd(
171        'Kernel::Output::HTML::Layout' => {
172            %Param,
173            SessionIDCookie => 1,
174            Debug           => $Self->{Debug},
175        },
176    );
177
178    my $DBCanConnect = $Kernel::OM->Get('Kernel::System::DB')->Connect();
179
180    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
181
182    if ( !$DBCanConnect ) {
183        $LayoutObject->CustomerFatalError(
184            Comment => Translatable('Please contact the administrator.'),
185        );
186    }
187    if ( $ParamObject->Error() ) {
188        $LayoutObject->CustomerFatalError(
189            Message => $ParamObject->Error(),
190            Comment => Translatable('Please contact the administrator.'),
191        );
192    }
193
194    # run modules if a version value exists
195    if ( !$Kernel::OM->Get('Kernel::System::Main')->Require("Kernel::Modules::$Param{Action}") ) {
196        $LayoutObject->CustomerFatalError(
197            Comment => Translatable('Please contact the administrator.'),
198        );
199        return 1;
200    }
201
202    # module registry
203    my $ModuleReg = $ConfigObject->Get('PublicFrontend::Module')->{ $Param{Action} };
204    if ( !$ModuleReg ) {
205        $Kernel::OM->Get('Kernel::System::Log')->Log(
206            Priority => 'error',
207            Message =>
208                "Module Kernel::Modules::$Param{Action} not registered in Kernel/Config.pm!",
209        );
210        $LayoutObject->CustomerFatalError(
211            Comment => Translatable('Please contact the administrator.'),
212        );
213        return;
214    }
215
216    # debug info
217    if ( $Self->{Debug} ) {
218        $Kernel::OM->Get('Kernel::System::Log')->Log(
219            Priority => 'debug',
220            Message  => 'Kernel::Modules::' . $Param{Action} . '->new',
221        );
222    }
223
224    my $FrontendObject = ( 'Kernel::Modules::' . $Param{Action} )->new(
225        UserID => 1,
226        %Param,
227        Debug => $Self->{Debug},
228    );
229
230    # debug info
231    if ( $Self->{Debug} ) {
232        $Kernel::OM->Get('Kernel::System::Log')->Log(
233            Priority => 'debug',
234            Message  => 'Kernel::Modules::' . $Param{Action} . '->run',
235        );
236    }
237
238    # ->Run $Action with $FrontendObject
239    $LayoutObject->Print( Output => \$FrontendObject->Run() );
240
241    # log request time
242    if ( $ConfigObject->Get('PerformanceLog') ) {
243        if ( ( !$QueryString && $Param{Action} ) || $QueryString !~ /Action=/ ) {
244            $QueryString = 'Action=' . $Param{Action} . '&Subaction=' . $Param{Subaction};
245        }
246        my $File = $ConfigObject->Get('PerformanceLog::File');
247        ## no critic
248        if ( open my $Out, '>>', $File ) {
249            ## use critic
250            print $Out time()
251                . '::Public::'
252                . ( time() - $Self->{PerformanceLogStart} )
253                . "::-::$QueryString\n";
254            close $Out;
255            $Kernel::OM->Get('Kernel::System::Log')->Log(
256                Priority => 'debug',
257                Message  => 'Response::Public: '
258                    . ( time() - $Self->{PerformanceLogStart} )
259                    . "s taken (URL:$QueryString)",
260            );
261        }
262        else {
263            $Kernel::OM->Get('Kernel::System::Log')->Log(
264                Priority => 'error',
265                Message  => "Can't write $File: $!",
266            );
267        }
268    }
269
270    return 1;
271}
272
273sub DESTROY {
274    my $Self = shift;
275
276    # debug info
277    if ( $Self->{Debug} ) {
278        $Kernel::OM->Get('Kernel::System::Log')->Log(
279            Priority => 'debug',
280            Message  => 'Global handle stopped.',
281        );
282    }
283
284    return 1;
285}
286
2871;
288
289=head1 TERMS AND CONDITIONS
290
291This software is part of the OTRS project (L<https://otrs.org/>).
292
293This software comes with ABSOLUTELY NO WARRANTY. For details, see
294the enclosed file COPYING for license information (GPL). If you
295did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>.
296
297=cut
298