Developer-Dashboard
view release on metacpan or search on metacpan
lib/Developer/Dashboard/Web/App.pm view on Meta::CPAN
}
elsif ( $type eq 'css' ) {
return 'text/css; charset=utf-8';
}
elsif ( $filename =~ /\.json$/i ) {
return 'application/json; charset=utf-8';
}
elsif ( $filename =~ /\.xml$/i ) {
return 'application/xml; charset=utf-8';
}
elsif ( $filename =~ /\.txt$/i ) {
return 'text/plain; charset=utf-8';
}
elsif ( $filename =~ /\.html?$/i ) {
return 'text/html; charset=utf-8';
}
elsif ( $filename =~ /\.svg$/i ) {
return 'image/svg+xml';
}
elsif ( $filename =~ /\.png$/i ) {
return 'image/png';
}
elsif ( $filename =~ /\.jpe?g$/i ) {
return 'image/jpeg';
}
elsif ( $filename =~ /\.gif$/i ) {
return 'image/gif';
}
elsif ( $filename =~ /\.webp$/i ) {
return 'image/webp';
}
elsif ( $filename =~ /\.ico$/i ) {
return 'image/x-icon';
}
else {
return 'application/octet-stream';
}
}
1;
__END__
=encoding UTF-8
=head1 NAME
Developer::Dashboard::Web::App - local web application for Developer Dashboard
=head1 SYNOPSIS
my $app = Developer::Dashboard::Web::App->new(
auth => $auth,
pages => $pages,
sessions => $sessions,
);
=head1 DESCRIPTION
This module handles the browser-facing dashboard routes, helper login flow,
page rendering modes, and page/action execution endpoints. It also provides
static file serving for JavaScript, CSS, and other assets from the public
directory structure (~/.developer-dashboard/dashboard/public/{js,css,others}).
The browser tab icon at C</favicon.ico> is served from the same layered
C<others> roots with a bundled fallback, and resolves before the authorization
gate because browsers request it implicitly on every page load.
Cross-site request forgery defense: every state-changing request (POST, PUT,
DELETE, PATCH) passes one origin check before any trust-tier dispatch. When
the request carries an C<Origin> header (or, absent that, a C<Referer>), its
authority must equal the request's own C<Host> header or name a trusted local
alias â a numeric loopback literal, the localhost hostname family, or a
configured C<web.ssl_subject_alt_names> entry, the same alias semantics the
loopback-admin trust check applies. Anything else, including the opaque
C<Origin: null>, is refused with an empty 403 on every tier: the
loopback-admin shortcut, helper sessions, and the machine API tier alike,
because browsers attach ambient credentials and loopback reachability to
cross-site requests automatically. Requests with neither header keep working,
since non-browser machine clients send neither while browsers always attach
C<Origin> to cross-site state-changing requests. The check also holds behind
the SSL front-proxy, which forwards TLS bytes unmodified, so the backend
compares against the browser's own C<Host> header.
That origin check cannot defend a C<GET>, because browsers omit C<Origin> on
same-origin GETs and a hostile page can drop its C<Referer> with a referrer
policy â yet C</ajax/E<lt>fileE<gt>> runs an operator-written saved handler as
a child process from a plain GET, on a tier that needs no cookie. So the same
choke point additionally refuses, on B<every> method, any request the browser
labelled C<Sec-Fetch-Site: cross-site> or C<same-site>, unless the
accompanying C<Origin>/C<Referer> names this dashboard or a trusted local
alias (the C<localhost>/C<127.0.0.1> pair is one host to the trust model and
two sites to the browser). C<Sec-Fetch-Site> is set by the browser itself and
is a forbidden header name, so page script can neither forge nor suppress it.
Requests carrying no fetch metadata are unaffected, which keeps machine
clients and browsers too old to send it working unchanged.
=head1 METHODS
=head2 new, handle
Construct and dispatch the local web application.
=head2 _serve_static_file($type, $filename)
Serves static files from the public directory.
Input: $type (js, css, or others subdirectory), $filename (requested filename).
Output: array reference of [status_code, content_type, body].
Security: Prevents directory traversal attacks and verifies files are within
the public directory before serving.
=head2 _static_path_contained($file_path, $allowed_roots)
Package function asserting that one resolved static asset path still lives
beneath an allowed public root after symlinks and parent-directory components
are resolved with C<Cwd::abs_path>, denying by default when no allowed roots
are supplied. Every static-serving entry point passes its lookup roots through
this check before opening a resolved path, including skill-namespaced assets,
whose allowed roots come from the skill dispatcher's layered
C<dashboards/public> trees.
Input: resolved candidate file path string and array reference of allowed root
directory path strings.
Output: boolean true when the resolved path is inside one existing allowed
root, otherwise false.
=head2 _get_content_type($type, $filename)
Determines the MIME type for a file based on its type and extension.
Input: $type (js, css, or others), $filename (requested filename).
Output: MIME type string suitable for Content-Type header.
Supports: JS, CSS, JSON, XML, HTML, SVG, PNG, JPEG, GIF, WebP, ICO, and others.
=for comment FULL-POD-DOC START
=head1 PURPOSE
This module is the main route backend for the browser application. It handles login and logout, saved and transient page render/source/edit routes, status endpoints, saved Ajax endpoints, and the auth checks that decide whether a request is local adm...
=head1 WHY IT EXISTS
It exists because the dashboard browser surface is large and security-sensitive. Centralizing route behavior, auth gating, saved-page handling, Ajax endpoints, layered C<config/api.json> machine auth, and response shaping keeps the product behavior c...
=head1 WHEN TO USE
Use this file when changing browser routes, helper login behavior, page render/source/edit flows, saved Ajax endpoints, or the runtime JSON and HTML responses for dashboard workspaces.
=head1 HOW TO USE
Construct it with the action runner, auth service, config service, page store, prompt, page resolver, page runtime, and session store, then hand it to the Dancer adapter or PSGI bootstrap. Route-specific behavior belongs here rather than in the trans...
=head1 WHAT USES IT
It is used by C<Developer::Dashboard::Web::DancerApp>, by C<app.psgi>, by the CLI web server wrapper, and by the broad web/browser regression suite that covers routes, auth, Ajax, and workspace behavior.
=head1 EXAMPLES
Example 1:
perl -Ilib -MDeveloper::Dashboard::Web::App -e 1
Do a direct compile-and-load check against the module from a source checkout.
Example 2:
prove -lv t/03-web-app.t t/08-web-update-coverage.t t/web_app_static_files.t
Run the focused regression tests that most directly exercise this module's behavior.
Example 3:
HARNESS_PERL_SWITCHES=-MDevel::Cover prove -lr t
Recheck the module under the repository coverage gate rather than relying on a load-only probe.
Example 4:
prove -lr t
Put any module-level change back through the entire repository suite before release.
=for comment FULL-POD-DOC END
=cut
( run in 0.703 second using v1.01-cache-2.11-cpan-9789f410c06 )