App-MFILE-WWW

 view release on metacpan or  search on metacpan

lib/App/MFILE/WWW/Resource.pm  view on Meta::CPAN




=head2 uri_too_long

Is the URI too long?

=cut

sub uri_too_long {
    my ( $self, $uri ) = @_;

    ( length $uri > $site->MFILE_URI_MAX_LENGTH )
        ? 1
        : 0;
}


=head2 is_authorized

Since all requests go through this function at a fairly early stage, we
leverage it to validate the session.

=cut

sub is_authorized {
    my ( $self ) = @_;

    $log->debug( "Entering " . __PACKAGE__ . "::is_authorized()" );

    my $r = $self->request;
    my $session = $self->session;
    my $remote_addr = $self->remote_addr;
    my $ce;

    #$log->debug( "Environment is " . Dumper( $r->{'env'} ) );
    $log->debug( "Session is " . Dumper( $session ) );

    # authorized session
    if ( $ce = $session->{'currentUser'} and
         $session->{'ip_addr'} and
         $session->{'ip_addr'} eq $remote_addr and
         _is_fresh( $session ) )
    {
        $log->debug( "is_authorized: Authorized session, employee " . $ce->{'nick'} );
        $session->{'last_seen'} = time;
        return 1;
    }

    # login attempt
    if ( $r->method eq 'POST' and
         $self->context->{'request_body'} and
         $self->context->{'request_body'}->{'method'} and
         $self->context->{'request_body'}->{'method'} =~ m/^LOGIN/i ) {
        $log->debug( "is_authorized: Login attempt - pass it on" );
        return 1;
    }

    # bypass login dialog?
    if ( $site->MFILE_WWW_BYPASS_LOGIN_DIALOG ) {
        $log->warn( "Bypassing login dialog! Using default credentials" );
        #
        # since the credentials are set in the configuration file, we only
        # need to check them once - the result of this check is placed in
        # META_LOGIN_BYPASS_STATE
        #
        if ( not defined $meta->META_LOGIN_BYPASS_STATE ) {
            $meta->set('META_LOGIN_BYPASS_STATE', 0);
            $session->{'ip_addr'} = $remote_addr;
            $session->{'last_seen'} = time;
            my $bypass_status = $self->validate_user_credentials( {
                'nam' => $site->MFILE_WWW_DEFAULT_LOGIN_CREDENTIALS->{'nam'},
                'pwd' => $site->MFILE_WWW_DEFAULT_LOGIN_CREDENTIALS->{'pwd'},
            } );
            if ( $bypass_status->level() eq 'OK' ) {
                $meta->set('META_LOGIN_BYPASS_STATE', 1);
            }
        }
        return $meta->META_LOGIN_BYPASS_STATE;
    }

    # unauthorized session
    $log->debug( "is_authorized fall-through: " . $r->method . " " . $self->request->path_info );
    return ( $r->method eq 'GET' ) ? 1 : 0;
}


=head2 _is_fresh

Takes a single argument, the PSGI session, which is assumed to contain a
C<last_seen> attribute containing the number of seconds since epoch when the
session was last seen.

=cut

sub _is_fresh {
    my ( $session ) = validate_pos( @_, { type => HASHREF } );

    return 0 unless my $last_seen = $session->{'last_seen'};

    return ( time - $last_seen > $site->MFILE_WWW_SESSION_EXPIRATION_TIME )
        ? 0
        : 1;
}


=head2 known_content_type

Looks at the 'Content-Type' header of POST requests, and generates
a "415 Unsupported Media Type" response if it is anything other than
'application/json'.

=cut

sub known_content_type {
    my ( $self, $content_type ) = @_;

    #$log->debug( "known_content_type: " . Dumper $content_type );
    # for GET requests, we don't care about the content
    return 1 if $self->request->method eq 'GET';

    # some requests may not specify a Content-Type at all
    return 0 if not defined $content_type;

    # unfortunately, Web::Machine sometimes sends the content-type
    # as a plain string, and other times as an
    # HTTP::Headers::ActionPack::MediaType object
    if ( ref( $content_type ) eq '' ) {
        return ( $content_type =~ m/application\/json/ ) ? 1 : 0;
    }
    if ( ref( $content_type ) eq 'HTTP::Headers::ActionPack::MediaType' ) {

lib/App/MFILE/WWW/Resource.pm  view on Meta::CPAN

    $r .= '            QUnit.config.autostart = false;';
    $r .= '        }';
    $r .= '    }';
    $r .= '},';

    # default waitSeconds is just 7, which is too little for production
    $r .= 'waitSeconds: 30';

    # end of require.config
    $r .= "});";

    # initialize configuration parameters that we need on JavaScript side
    $r .= 'requirejs.config({ config: {';
    $r .= '\'cf\': { ';

    # appName, appVersion
    $r .= 'appName: \'' . $site->MFILE_APPNAME . '\',';
    $r .= 'appVersion: \'' . $meta->META_MFILE_APPVERSION . '\',';

    # standaloneMode (boolean; false means "derived distro mode")
    $r .= 'standaloneMode: \'' . ( $meta->META_WWW_STANDALONE_MODE ? 'true' : 'false' ) . '\',';

    # currentUser
    $r .= "currentUser: " . ( $ce ? to_json( $ce ) : 'null' ) . ',';
    $r .= "currentUserPriv: " . ( $cepriv ? "\'$cepriv\'" : 'null' ) . ',';

    # loginDialog
    $r .= 'loginDialogChallengeText: \'' . $site->MFILE_WWW_LOGIN_DIALOG_CHALLENGE_TEXT . '\',';
    $r .= 'loginDialogMaxLengthUsername: ' . $site->MFILE_WWW_LOGIN_DIALOG_MAXLENGTH_USERNAME . ',';
    $r .= 'loginDialogMaxLengthPassword: ' . $site->MFILE_WWW_LOGIN_DIALOG_MAXLENGTH_PASSWORD . ',';

    # session data
    $r .= 'displaySessionData: ' . ( $site->MFILE_WWW_DISPLAY_SESSION_DATA ? 'true' : 'false' ) . ',';
    if ( $site->MFILE_WWW_DISPLAY_SESSION_DATA ) {
        $r .= 'sessionID: \'' . $self->session_id . '\',';
        $r .= 'sessionLastSeen: \'' . ( exists $self->session->{'last_seen'} ? $self->session->{'last_seen'} : 'never' ) . '\',';
    }

    # REST server URI
    if ( defined( $site->DOCHAZKA_WWW_BACKEND_URI ) ) {
        $r .= 'restURI: \'' . $site->DOCHAZKA_WWW_BACKEND_URI . '\',';
    }

    # dummyParam in last position so we don't have to worry about comma/no comma
    $r .= 'dummyParam: null,';

    # unit tests running?
    $r .= "testing: " . ( $testing ? 'true' : 'false' );

    $r .= '} } });';
    $r .= '</script>';
    return $r;
} 


=head2 login_status

Once the username and password are known (either from C<process_post> via the
login AJAX request generated by the login dialog, or from the site
configuration via the MFILE_WWW_BYPASS_LOGIN_DIALOG mechanism), the
C<validate_user_credentials> method is called. That method is implemented by
the derived application, so it can validate user credentials however it likes.
The C<validate_user_credentials> method is then expected to call this method -
C<login_status> - to generate a status object from the results of the user
credentials validation.

Now, C<App::MFILE::WWW> does expect the C<validate_user_credentials> method to
provide the results of user credentials validation in a peculiar format,
hinging on the argument C<$code>, where a value of 200 indicates successful
validation and any other value indicates a failure.

=cut

sub login_status {
    my ( $self, $code, $message, $body_json ) = @_;

    my $status;

    if ( $code == 200 ) {
        $self->session->{'ip_addr'} = $self->remote_addr;
        my $cu = $body_json->{'payload'}->{'emp'};
        delete $cu->{'passhash'};
        delete $cu->{'salt'};
        $self->session->{'currentUser'} = $cu;
        $self->session->{'currentUserPriv'} = $body_json->{'payload'}->{'priv'};
        $self->session->{'last_seen'} = time;
        $log->debug(
            "Login successful, currentUser is now " .
            Dumper( $body_json->{'payload'}->{'emp'} ) .
            " and privilege level is " . $body_json->{'payload'}->{'priv'}
        );
        $status = $CELL->status_ok( 'MFILE_WWW_LOGIN_OK', payload => $body_json->{'payload'} );
    } else {
        $self->session({});
        $log->debug( "Login unsuccessful, reset session" );
        $status = $CELL->status_not_ok(
            'MFILE_WWW_LOGIN_FAIL: %s',
            args => [ $code ],
            payload => { code => $code, message => $message },
        );
    }
    $self->response->header( 'Content-Type' => 'application/json' );
    $self->response->body( to_json( $status->expurgate ) );
    return $status;
}


=head2 ua

Returns the LWP::UserAgent object obtained from the lookup table.
Creates it first if necessary.

=cut

sub ua {
    my $self = shift;
    $log->debug( "Entering " . __PACKAGE__ . "::ua()" );
    my $id = $self->session_id;
    $log->debug( "ua: session_id is $id" );

    # already in lookup table
    if ( exists $ualt->{$id} ) {
         $log->debug( "Session $id already has a LWP::UserAgent object" );
         return $ualt->{$id};
    }

    # not in lookup table yet
    my $tf = "";



( run in 1.015 second using v1.01-cache-2.11-cpan-39bf76dae61 )