mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-06-29 18:50:00 +02:00
e4ffd74068
* security: harden against XSS, ReDoS, path traversal, and injection Defensive fixes across the server, storage, and viewer: - XSS (CWE-79): sanitise rendered notebooks with DOMPurify, escape file names interpolated into AngularJS expressions (escapeNgString), set Mermaid securityLevel to 'strict', and stop urlRel2abs from returning javascript:/vbscript:/data:text/html URLs. - Path traversal / zip-slip (CWE-22/23/24): validate URL-derived path components before they reach the storage layer (file/webview routes + StorageBase.assertSafePath) and sanitise zip entry names on extract for both the filesystem and S3 backends. - ReDoS (CWE-1333): escape anonymization terms with catastrophic backtracking shapes to literals instead of compiling them as regexes. - Secret hardening (CWE-798): require SESSION_SECRET / OAuth creds / DB password in production, random dev SESSION_SECRET fallback. - Rate-limit spoofing (CWE-290): derive request.ip via trust-proxy hop count instead of the client-settable cf-connecting-ip header. - NoSQL injection (CWE-943): allow only plain field paths as admin sort keys. - Reject malformed streamer requests missing required string fields. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(ui): make gists reachable/visible and clarify the ZIP button - Gist & PR routes now accept a trailing slash (/gist/:id/:path*?), so the dashboard links (which end in "/") resolve to the gist/PR page instead of falling through to the 404 route (#725). - Gist viewer picks the default tab after content loads, defaulting to "files" when files exist; previously the ng-init ran before the async load and a files-only gist rendered blank under the hidden comments tab. - Explorer toolbar: relabel ZIP to "Full repo ZIP" with a tooltip, and add tooltips to Raw/Download clarifying they apply to the current file (#721). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: report SAML-enforced orgs clearly instead of "token expired" When a repo's organization enforces SAML SSO, GitHub returns a 403 whose message differs from the OAuth-App-restriction case. That 403 fell through to the generic handler and surfaced as "token_expired", pushing users to re-login when the real fix is authorizing their token for the org. Detect the "SAML enforcement" message and raise a dedicated, actionable error instead (#379, #550). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * security: catch nested quantified groups in ReDoS guard and backslash path traversal - hasCatastrophicBacktracking now scans across nested parens ([\s\S]*?) so shapes like ((a+))+ are detected; comment reframed as a heuristic backstop rather than a proof. - file route path-traversal check now rejects backslash separators and a leading backslash, covering Windows-style "..\" payloads (CWE-22/25). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(dev): track dev-proxy script, ignore .DS_Store and .claude/ scripts/dev-proxy.js is referenced by the "dev:ui" npm script but was never committed, breaking the command on a fresh clone. Add it and ignore local-only macOS/Claude Code files. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
128 lines
4.5 KiB
HTML
128 lines
4.5 KiB
HTML
<div class="explorer-page" ng-init="sidebarCollapsed = window.matchMedia && window.matchMedia('(max-width: 767px)').matches">
|
|
<button
|
|
class="sidebar-toggle"
|
|
ng-show="files.length"
|
|
ng-click="sidebarCollapsed = !sidebarCollapsed"
|
|
aria-label="{{sidebarCollapsed ? 'Show files' : 'Hide files'}}"
|
|
>
|
|
<i class="fas" ng-class="sidebarCollapsed ? 'fa-folder-open' : 'fa-times'"></i>
|
|
<span ng-bind="sidebarCollapsed ? 'Files' : 'Close'"></span>
|
|
</button>
|
|
|
|
<div class="leftCol" ng-show="files.length" ng-class="{'collapsed': sidebarCollapsed}">
|
|
<div class="leftCol-head">
|
|
<span class="leftCol-eyebrow">Files</span>
|
|
<button class="leftCol-close" ng-click="sidebarCollapsed = true" aria-label="Close files">
|
|
<i class="fas fa-times"></i>
|
|
</button>
|
|
</div>
|
|
<div class="leftCol-search">
|
|
<div class="tree-search-box">
|
|
<i class="fas tree-search-icon" ng-class="fileSearchLoading ? 'fa-spinner fa-spin' : 'fa-search'"></i>
|
|
<input
|
|
type="text"
|
|
class="tree-search-input"
|
|
placeholder="Search files"
|
|
ng-model="fileSearchQuery"
|
|
ng-model-options="{ debounce: 300 }"
|
|
ng-change="onFileSearchChange()"
|
|
aria-label="Search files"
|
|
/>
|
|
<kbd class="tree-search-kbd" ng-hide="fileSearchQuery">{{isMac ? '⌘' : 'Ctrl+'}}K</kbd>
|
|
<button
|
|
class="tree-search-clear"
|
|
ng-show="fileSearchQuery"
|
|
ng-click="fileSearchQuery = ''; onFileSearchChange()"
|
|
aria-label="Clear search"
|
|
>×</button>
|
|
</div>
|
|
</div>
|
|
<div class="leftCol-project-header">
|
|
<span class="project-name" ng-bind="repoId"></span>
|
|
<span class="project-file-count">{{fileCounts[''] || files.length}} files</span>
|
|
</div>
|
|
<div class="leftCol-body">
|
|
<div
|
|
ng-if="options.truncatedFolders.length > 0"
|
|
class="paper-inline-warning"
|
|
role="alert"
|
|
>
|
|
<i class="fas fa-exclamation-triangle"></i>
|
|
{{ 'WARNINGS.repo_truncated' | translate }}
|
|
</div>
|
|
<tree class="files" file="files" search-query="fileSearchQuery" search-results="fileSearchResults"></tree>
|
|
</div>
|
|
<div class="leftCol-foot">
|
|
<span
|
|
class="last-update"
|
|
data-toggle="tooltip"
|
|
data-placement="top"
|
|
title="{{options.lastUpdateDate}}"
|
|
>
|
|
Updated {{options.lastUpdateDate|date}}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
class="leftCol-backdrop"
|
|
ng-show="files.length && !sidebarCollapsed"
|
|
ng-click="sidebarCollapsed = true"
|
|
></div>
|
|
|
|
<div class="explorer-main">
|
|
<div class="status-bar">
|
|
<ol class="breadcrumb paths" aria-label="Path">
|
|
<li class="breadcrumb-item" ng-repeat="p in paths" ng-bind="p"></li>
|
|
</ol>
|
|
<div class="status-bar-actions">
|
|
<a
|
|
ng-if="options.isAdmin || options.isOwner"
|
|
ng-href="/anonymize/{{repoId}}"
|
|
class="btn btn-sm"
|
|
aria-label="Edit"
|
|
><i class="far fa-edit"></i><span class="d-none d-md-inline"> Edit</span></a
|
|
>
|
|
<a
|
|
ng-show="content != null"
|
|
ng-href="{{url}}"
|
|
target="__self"
|
|
class="btn btn-sm"
|
|
aria-label="View raw current file"
|
|
title="View the raw content of the current file"
|
|
><i class="fas fa-file-alt"></i><span class="d-none d-md-inline"> Raw</span></a
|
|
>
|
|
<a
|
|
ng-show="content != null"
|
|
ng-href="{{url}}&download=true"
|
|
target="__self"
|
|
class="btn btn-sm"
|
|
aria-label="Download current file"
|
|
title="Download the current file"
|
|
><i class="fas fa-download"></i><span class="d-none d-md-inline"> Download</span></a
|
|
>
|
|
<a
|
|
ng-if="options.download"
|
|
ng-href="/api/repo/{{repoId}}/zip"
|
|
target="__self"
|
|
class="btn btn-sm"
|
|
aria-label="Download full repository as ZIP"
|
|
title="Download the full repository as a ZIP archive"
|
|
><i class="fas fa-file-archive"></i><span class="d-none d-md-inline"> Full repo ZIP</span></a
|
|
>
|
|
<a
|
|
ng-if="options.hasWebsite"
|
|
ng-href="/w/{{repoId}}/"
|
|
target="__self"
|
|
class="btn btn-sm"
|
|
aria-label="Website"
|
|
><i class="fas fa-globe"></i><span class="d-none d-md-inline"> Website</span></a
|
|
>
|
|
</div>
|
|
</div>
|
|
<div class="explorer-content">
|
|
<ng-include src="'./partials/pageView.htm'"></ng-include>
|
|
</div>
|
|
</div>
|
|
</div>
|