mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-10-19 06:07:21 +02:00
fix: support gists through GitHub App login (#875)
* fix: prompt OAuth reconnection when gist credentials are rejected * fix: support gist reads through GitHub App user grants * test: adapt truncated gist regression to provider selection * fix: address gist reconnect visibility and token renewal review * fix: verify App authorization before revoking OAuth
This commit is contained in:
1 parent
4fd31a59c8
commit
db966356ec
14 files changed
+283
-54
No files matched your search
@@ -52,7 +52,7 @@ Request no repository write permissions. Verify PR issue-comment reads with the
|
|||||||
|
|
||||||
Pages lookup specifically requires Pages read; lack of Pages access must not make ordinary repository import fail. See [Pages endpoint permissions](https://docs.github.com/en/rest/pages/pages#get-a-github-pages-site).
|
Pages lookup specifically requires Pages read; lack of Pages access must not make ordinary repository import fail. See [Pages endpoint permissions](https://docs.github.com/en/rest/pages/pages#get-a-github-pages-site).
|
||||||
|
|
||||||
Gists are a separate capability. Keep existing gist resources on OAuth in the first release, and show that requirement for App-only users. Do not send installation tokens to gist endpoints. Evaluate App user-token support for gist content, comments and raw downloads as a later compatibility step using the [gist API reference](https://docs.github.com/en/rest/gists/gists). OAuth retirement depends on resolving this gap.
|
Gists use App user tokens when available, with refresh and provider-specific reconnect handling. Do not send installation tokens to gist endpoints. Reading gist content and comments requires no additional App permissions; see the [gist API reference](https://docs.github.com/en/rest/gists/gists). Accounts without an App connection retain OAuth access.
|
||||||
|
|
||||||
### Persistence and credential lifecycle
|
### Persistence and credential lifecycle
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ Keep rate-limit behavior across token renewal by using provider-aware quota iden
|
|||||||
4. Provide a migration preview listing eligible resources and blocked resources, with reasons such as repository not selected, approval pending, missing permission or gist compatibility.
|
4. Provide a migration preview listing eligible resources and blocked resources, with reasons such as repository not selected, approval pending, missing permission or gist compatibility.
|
||||||
5. On explicit migration, verify App access and read the resource's configured commit (or PR) before conditionally updating its binding. Preserve all anonymization settings, URLs and caches. A partial batch reports per-resource results and can be rerun; jobs read the latest binding and reject stale results if the binding changes while running.
|
5. On explicit migration, verify App access and read the resource's configured commit (or PR) before conditionally updating its binding. Preserve all anonymization settings, URLs and caches. A partial batch reports per-resource results and can be rerun; jobs read the latest binding and reject stale results if the binding changes while running.
|
||||||
6. Display each resource's connection and reconnect action. Connecting the App alone does not migrate resources or revoke OAuth.
|
6. Display each resource's connection and reconnect action. Connecting the App alone does not migrate resources or revoke OAuth.
|
||||||
7. Offer OAuth disconnect after listing remaining dependencies, including gists. A new sign-in does not reduce an existing OAuth grant's scope. Complete removal of the broad grant requires explicit revocation; warn about affected resources in that concrete disconnect flow.
|
7. Offer OAuth disconnect after listing remaining repository and pull-request dependencies. Gists use the App user connection automatically. A new sign-in does not reduce an existing OAuth grant's scope. Complete removal of the broad grant requires explicit revocation; warn about affected resources in that concrete disconnect flow.
|
||||||
|
|
||||||
## Revocation, webhooks and retained content
|
## Revocation, webhooks and retained content
|
||||||
|
|
||||||
|
|||||||
@@ -108,11 +108,10 @@ Existing installation bindings retain their installation checks.
|
|||||||
This uses GitHub's documented [public resource access for App user tokens](https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/choosing-permissions-for-a-github-app).
|
This uses GitHub's documented [public resource access for App user tokens](https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/choosing-permissions-for-a-github-app).
|
||||||
|
|
||||||
The explicit **Use existing OAuth access** choice handles repositories not yet
|
The explicit **Use existing OAuth access** choice handles repositories not yet
|
||||||
available through the App. An App error never silently selects OAuth. Gists
|
available through the App. An App error never silently selects OAuth. Gists prefer
|
||||||
continue using OAuth. An App-only user entering a gist URL is prompted to connect
|
an existing App user grant and otherwise retain legacy OAuth access. Rejected
|
||||||
OAuth, with the current repository permission scope explained. The form draft
|
credentials prompt reconnection to the same provider. The form draft is saved for
|
||||||
is saved for 30 minutes and restored after authorization. Users with an existing
|
30 minutes and restored after authorization. OAuth remains available on the
|
||||||
OAuth connection can use it immediately. OAuth remains available on the
|
|
||||||
Connections page, separate from sign-in.
|
Connections page, separate from sign-in.
|
||||||
|
|
||||||
**GitHub connections** lists each resource's current connection. First check
|
**GitHub connections** lists each resource's current connection. First check
|
||||||
@@ -121,8 +120,12 @@ commit or PR and conditionally updates the binding; it preserves the anonymous
|
|||||||
URL, settings and existing content. Busy resources must finish before switching.
|
URL, settings and existing content. Busy resources must finish before switching.
|
||||||
Each resource can be switched back to a verified existing OAuth grant.
|
Each resource can be switched back to a verified existing OAuth grant.
|
||||||
|
|
||||||
OAuth can be explicitly revoked once all dependent resources, including gists,
|
Gists use the App user token when an App connection exists, including token refresh.
|
||||||
have been migrated or removed and a working App sign-in remains. Merely connecting
|
Reading gist content and comments needs no additional GitHub App permissions or
|
||||||
|
repository installation. Legacy OAuth remains available for accounts without an App connection.
|
||||||
|
|
||||||
|
OAuth can be explicitly revoked once dependent repositories and pull requests
|
||||||
|
have been migrated or removed and a working App sign-in remains. Gists do not block revocation. Merely connecting
|
||||||
the App does not revoke or narrow the OAuth grant.
|
the App does not revoke or narrow the OAuth grant.
|
||||||
|
|
||||||
## Access lifecycle and rollback
|
## Access lifecycle and rollback
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"core.min.js": "core.3b07189932.min.js",
|
"core.min.js": "core.3b07189932.min.js",
|
||||||
"vendor.min.js": "vendor.9e4516e8b9.min.js",
|
"vendor.min.js": "vendor.a1e4517da7.min.js",
|
||||||
"mermaid.min.js": "mermaid.f848a72d16.min.js",
|
"mermaid.min.js": "mermaid.f848a72d16.min.js",
|
||||||
"all.min.css": "all.947ab87f1c.min.css",
|
"all.min.css": "all.947ab87f1c.min.css",
|
||||||
"markdown.min.js": "markdown.44f2e93820.min.js",
|
"markdown.min.js": "markdown.44f2e93820.min.js",
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<button type="button" :aria-pressed="githubConnection === 'github-app'" :disabled="githubConnection === 'github-app'" @click="chooseGitHubConnection('github-app')"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-shield"></use></svg> <span class="sr-only">Read-only </span>GitHub App</button>
|
<button type="button" :aria-pressed="githubConnection === 'github-app'" :disabled="githubConnection === 'github-app'" @click="chooseGitHubConnection('github-app')"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-shield"></use></svg> <span class="sr-only">Read-only </span>GitHub App</button>
|
||||||
<button type="button" :aria-pressed="githubConnection === 'oauth'" :disabled="githubConnection === 'oauth'" @click="chooseGitHubConnection('oauth')">Legacy OAuth</button>
|
<button type="button" :aria-pressed="githubConnection === 'oauth'" :disabled="githubConnection === 'oauth'" @click="chooseGitHubConnection('oauth')">Legacy OAuth</button>
|
||||||
</div>
|
</div>
|
||||||
<span class="connection-badge" v-if="isUpdate || detectedType === 'gist'">{{ detectedType !== 'gist' && githubConnection === 'github-app' ? 'Read-only GitHub App' : 'Legacy OAuth' }}</span>
|
<span class="connection-badge" v-if="isUpdate || detectedType === 'gist'">{{ (detectedType === 'gist' ? githubConnections?.gistConnection === 'github-app' : githubConnection === 'github-app') ? 'Read-only GitHub App' : 'Legacy OAuth' }}</span>
|
||||||
</aside>
|
</aside>
|
||||||
</div>
|
</div>
|
||||||
<input id="sourceUrl-landing" type="text" class="form-control form-control-lg" placeholder="https://github.com/owner/repository" v-field="{ state: viewState, set: value => { sourceUrl = value }, value: sourceUrl, form: null, options: { debounce: {default: 1000, blur: 0, click: 0}, updateOn: 'default blur click' }, change: () => { urlSelected() } }">
|
<input id="sourceUrl-landing" type="text" class="form-control form-control-lg" placeholder="https://github.com/owner/repository" v-field="{ state: viewState, set: value => { sourceUrl = value }, value: sourceUrl, form: null, options: { debounce: {default: 1000, blur: 0, click: 0}, updateOn: 'default blur click' }, change: () => { urlSelected() } }">
|
||||||
@@ -27,12 +27,6 @@
|
|||||||
<small class="form-text" style="color: var(--ink-muted);">
|
<small class="form-text" style="color: var(--ink-muted);">
|
||||||
Repository, pull request (…/pull/42) and gist (gist.github.com/…) URLs are all accepted.
|
Repository, pull request (…/pull/42) and gist (gist.github.com/…) URLs are all accepted.
|
||||||
</small>
|
</small>
|
||||||
<aside class="alert alert-info" role="status" v-if="detectedType === 'gist' && gistOAuthRequired">
|
|
||||||
<p>Connect GitHub OAuth to access gists. Your account and existing anonymizations stay the same, and your draft will be restored when you return.</p>
|
|
||||||
<p>GitHub's legacy OAuth connection includes write access to private repositories.</p>
|
|
||||||
<button type="button" class="btn btn-ink" @click="connectGistOAuth()" v-if="githubConnections?.oauthEnabled">Connect GitHub OAuth to access gists</button>
|
|
||||||
<p v-else>GitHub OAuth is currently unavailable. Please try again later.</p>
|
|
||||||
</aside>
|
|
||||||
<aside class="repo-access-details" aria-label="GitHub access" v-if="!sourceUrl && githubConnections?.appEnabled && githubConnections.appConnected && githubConnections.oauthConnected">
|
<aside class="repo-access-details" aria-label="GitHub access" v-if="!sourceUrl && githubConnections?.appEnabled && githubConnections.appConnected && githubConnections.oauthConnected">
|
||||||
<div class="repo-access-main">
|
<div class="repo-access-main">
|
||||||
<div class="repo-access-controls">
|
<div class="repo-access-controls">
|
||||||
@@ -65,6 +59,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
<aside class="alert alert-info" role="status" v-if="detectedType === 'gist' && gistAppRequired">
|
||||||
|
<p>Reconnect your GitHub account to read this gist. Your draft will be restored when you return.</p>
|
||||||
|
<button type="button" class="btn btn-ink" @click="connectGistApp()">Connect GitHub App to access gists</button>
|
||||||
|
</aside>
|
||||||
|
<aside class="alert alert-info" role="status" v-if="detectedType === 'gist' && gistOAuthRequired">
|
||||||
|
<p>Connect GitHub OAuth to access gists. Your account and existing anonymizations stay the same, and your draft will be restored when you return.</p>
|
||||||
|
<p>GitHub's legacy OAuth connection includes write access to private repositories.</p>
|
||||||
|
<button type="button" class="btn btn-ink" @click="connectGistOAuth()" v-if="githubConnections?.oauthEnabled">Connect GitHub OAuth to access gists</button>
|
||||||
|
<p v-else>GitHub OAuth is currently unavailable. Please try again later.</p>
|
||||||
|
</aside>
|
||||||
|
|
||||||
<nav class="anonymize-mobile-tabs" role="tablist" aria-label="Anonymization workspace">
|
<nav class="anonymize-mobile-tabs" role="tablist" aria-label="Anonymization workspace">
|
||||||
<button id="workspace-settings-tab" role="tab" type="button" :aria-selected="mobilePane === 'settings'" aria-controls="workspace-settings" :tabindex="mobilePane === 'settings' ? 0 : -1" @keydown="previewTabKeydown($event)" @click="selectMobilePane('settings')">Settings</button>
|
<button id="workspace-settings-tab" role="tab" type="button" :aria-selected="mobilePane === 'settings'" aria-controls="workspace-settings" :tabindex="mobilePane === 'settings' ? 0 : -1" @keydown="previewTabKeydown($event)" @click="selectMobilePane('settings')">Settings</button>
|
||||||
<button id="workspace-preview-tab" role="tab" type="button" :aria-selected="mobilePane === 'preview'" aria-controls="workspace-preview" :tabindex="mobilePane === 'preview' ? 0 : -1" @keydown="previewTabKeydown($event)" @click="selectMobilePane('preview')">Reviewer preview</button>
|
<button id="workspace-preview-tab" role="tab" type="button" :aria-selected="mobilePane === 'preview'" aria-controls="workspace-preview" :tabindex="mobilePane === 'preview' ? 0 : -1" @keydown="previewTabKeydown($event)" @click="selectMobilePane('preview')">Reviewer preview</button>
|
||||||
@@ -86,7 +91,7 @@
|
|||||||
<button type="button" :aria-pressed="githubConnection === 'github-app'" :disabled="githubConnection === 'github-app'" @click="chooseGitHubConnection('github-app')"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-shield"></use></svg> <span class="sr-only">Read-only </span>GitHub App</button>
|
<button type="button" :aria-pressed="githubConnection === 'github-app'" :disabled="githubConnection === 'github-app'" @click="chooseGitHubConnection('github-app')"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-shield"></use></svg> <span class="sr-only">Read-only </span>GitHub App</button>
|
||||||
<button type="button" :aria-pressed="githubConnection === 'oauth'" :disabled="githubConnection === 'oauth'" @click="chooseGitHubConnection('oauth')">Legacy OAuth</button>
|
<button type="button" :aria-pressed="githubConnection === 'oauth'" :disabled="githubConnection === 'oauth'" @click="chooseGitHubConnection('oauth')">Legacy OAuth</button>
|
||||||
</div>
|
</div>
|
||||||
<span class="connection-badge" v-if="isUpdate || detectedType === 'gist'">{{ detectedType !== 'gist' && githubConnection === 'github-app' ? 'Read-only GitHub App' : 'Legacy OAuth' }}</span>
|
<span class="connection-badge" v-if="isUpdate || detectedType === 'gist'">{{ (detectedType === 'gist' ? githubConnections?.gistConnection === 'github-app' : githubConnection === 'github-app') ? 'Read-only GitHub App' : 'Legacy OAuth' }}</span>
|
||||||
</aside>
|
</aside>
|
||||||
</div>
|
</div>
|
||||||
<input type="text" class="form-control" name="sourceUrl" id="sourceUrl" :disabled="isUpdate && detectedType !== 'repo'" placeholder="Paste a GitHub repo or pull request URL" v-field="{ state: viewState, set: value => { sourceUrl = value }, value: sourceUrl, form: "anonymize", options: { debounce: {default: 1000, blur: 0, click: 0}, updateOn: 'default blur click' }, change: () => { urlSelected() } }" :class="{'is-invalid': anonymize?.sourceUrl?.invalid}">
|
<input type="text" class="form-control" name="sourceUrl" id="sourceUrl" :disabled="isUpdate && detectedType !== 'repo'" placeholder="Paste a GitHub repo or pull request URL" v-field="{ state: viewState, set: value => { sourceUrl = value }, value: sourceUrl, form: "anonymize", options: { debounce: {default: 1000, blur: 0, click: 0}, updateOn: 'default blur click' }, change: () => { urlSelected() } }" :class="{'is-invalid': anonymize?.sourceUrl?.invalid}">
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<section v-if="connections.appEnabled">
|
<section v-if="connections.appEnabled">
|
||||||
<div class="connection-top"><i class="fab fa-github" aria-hidden="true"></i><span class="connection-badge">Recommended</span></div>
|
<div class="connection-top"><i class="fab fa-github" aria-hidden="true"></i><span class="connection-badge">Recommended</span></div>
|
||||||
<div class="connection-title"><h2>GitHub App</h2><span class="connection-status" :class="{'is-connected': connections.appConnected && !connections.appError}">{{ connections.appError ? 'Needs attention' : connections.appConnected ? 'Connected' : 'Not connected' }}</span></div>
|
<div class="connection-title"><h2>GitHub App</h2><span class="connection-status" :class="{'is-connected': connections.appConnected && !connections.appError}">{{ connections.appError ? 'Needs attention' : connections.appConnected ? 'Connected' : 'Not connected' }}</span></div>
|
||||||
<p>Read-only access to the repositories you choose.</p>
|
<p>Read-only access to gists and the repositories you choose.</p>
|
||||||
<p class="paper-inline-alert paper-inline-alert-error" v-if="connections.appError" role="alert">{{ connections.appError }}. Reconnect to restore access.</p>
|
<p class="paper-inline-alert paper-inline-alert-error" v-if="connections.appError" role="alert">{{ connections.appError }}. Reconnect to restore access.</p>
|
||||||
<div class="connection-actions">
|
<div class="connection-actions">
|
||||||
<a class="btn btn-ink" v-if="connections.appConnected && !connections.appError" target="_self" href="/github/app/install">Manage repository access <svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-external-link"></use></svg></a>
|
<a class="btn btn-ink" v-if="connections.appConnected && !connections.appError" target="_self" href="/github/app/install">Manage repository access <svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-external-link"></use></svg></a>
|
||||||
@@ -27,13 +27,13 @@
|
|||||||
<section>
|
<section>
|
||||||
<div class="connection-top"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-key"></use></svg><span class="connection-badge connection-badge-muted">Legacy</span></div>
|
<div class="connection-top"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-key"></use></svg><span class="connection-badge connection-badge-muted">Legacy</span></div>
|
||||||
<div class="connection-title"><h2>GitHub OAuth</h2><span class="connection-status" :class="{'is-connected': connections.oauthConnected}">{{ connections.oauthConnected ? 'Connected' : 'Not connected' }}</span></div>
|
<div class="connection-title"><h2>GitHub OAuth</h2><span class="connection-status" :class="{'is-connected': connections.oauthConnected}">{{ connections.oauthConnected ? 'Connected' : 'Not connected' }}</span></div>
|
||||||
<p>For existing OAuth anonymizations and gists.</p>
|
<p>For existing OAuth anonymizations.</p>
|
||||||
<p class="connection-help">This connection uses GitHub's broader repository permissions. Existing work keeps using it until you switch below.</p>
|
<p class="connection-help">This connection uses GitHub's broader repository permissions. Existing work keeps using it until you switch below.</p>
|
||||||
<a v-if="connections.oauthEnabled" target="_self" href="/github/login" class="btn btn-outline-ink">{{ connections.oauthConnected ? 'Reconnect OAuth' : 'Connect legacy OAuth' }}</a>
|
<a v-if="connections.oauthEnabled" target="_self" href="/github/login" class="btn btn-outline-ink">{{ connections.oauthConnected ? 'Reconnect OAuth' : 'Connect legacy OAuth' }}</a>
|
||||||
<div class="connection-revoke" v-if="connections.oauthConnected">
|
<div class="connection-revoke" v-if="connections.oauthConnected">
|
||||||
<p v-if="connections.gistCount">{{ connections.gistCount }} gist(s) still require OAuth.</p>
|
<p v-if="connections.gistCount">{{ connections.gistCount }} gist(s) use your GitHub App connection when available.</p>
|
||||||
<p>Switch all dependent repositories before revoking access. Gists still require OAuth.</p>
|
<p>Switch all dependent repositories before revoking access. Gists can use your GitHub App connection.</p>
|
||||||
<button v-if="connections.appConnected" class="connection-link connection-danger" :disabled="busy || connections.gistCount || connections.resources.some(r => r.connection === 'oauth')" @click="disconnectOAuth()">Revoke OAuth access</button>
|
<button v-if="connections.appConnected" class="connection-link connection-danger" :disabled="busy || connections.resources.some(r => r.connection === 'oauth')" @click="disconnectOAuth()">Revoke OAuth access</button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -162,8 +162,8 @@
|
|||||||
<div class="q">
|
<div class="q">
|
||||||
<a href="/faq#permissions">What access does GitHub sign-in require?</a>
|
<a href="/faq#permissions">What access does GitHub sign-in require?</a>
|
||||||
<p>
|
<p>
|
||||||
The GitHub App has read-only access to the repositories you choose.
|
The GitHub App has read-only access to gists and the repositories you choose.
|
||||||
Legacy OAuth uses broader permissions and is still needed for gists.
|
Legacy OAuth uses broader permissions.
|
||||||
Anonymous GitHub never writes to your repositories.
|
Anonymous GitHub never writes to your repositories.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+12
-5
@@ -1147,11 +1147,16 @@ export const anonymizeController = function (state, http, html, params, location
|
|||||||
state.githubConnection = undefined;
|
state.githubConnection = undefined;
|
||||||
state.githubConnections = null;
|
state.githubConnections = null;
|
||||||
state.gistOAuthRequired = false;
|
state.gistOAuthRequired = false;
|
||||||
|
state.gistAppRequired = false;
|
||||||
const saveGitHubDraft = () => {
|
const saveGitHubDraft = () => {
|
||||||
const draft = {};
|
const draft = {};
|
||||||
for (const key of ["sourceUrl", "terms", "repoId", "pullRequestId", "gistId", "source", "options", "conference", "githubConnection"]) draft[key] = state[key];
|
for (const key of ["sourceUrl", "terms", "repoId", "pullRequestId", "gistId", "source", "options", "conference", "githubConnection"]) draft[key] = state[key];
|
||||||
sessionStorage.setItem("github-access-draft", JSON.stringify({ path: location.path(), savedAt: Date.now(), draft }));
|
sessionStorage.setItem("github-access-draft", JSON.stringify({ path: location.path(), savedAt: Date.now(), draft }));
|
||||||
};
|
};
|
||||||
|
state.connectGistApp = () => {
|
||||||
|
saveGitHubDraft();
|
||||||
|
window.location.href = "/github/app/login?returnTo=" + encodeURIComponent(location.path());
|
||||||
|
};
|
||||||
state.connectGistOAuth = () => {
|
state.connectGistOAuth = () => {
|
||||||
saveGitHubDraft();
|
saveGitHubDraft();
|
||||||
window.location.href = "/github/login?returnTo=" + encodeURIComponent(location.path());
|
window.location.href = "/github/login?returnTo=" + encodeURIComponent(location.path());
|
||||||
@@ -1450,6 +1455,7 @@ export const anonymizeController = function (state, http, html, params, location
|
|||||||
state.html_readme = "";
|
state.html_readme = "";
|
||||||
state.detectedType = null;
|
state.detectedType = null;
|
||||||
state.gistOAuthRequired = false;
|
state.gistOAuthRequired = false;
|
||||||
|
state.gistAppRequired = false;
|
||||||
|
|
||||||
state._preservingDraft = preserveSelection;
|
state._preservingDraft = preserveSelection;
|
||||||
try {
|
try {
|
||||||
@@ -1770,11 +1776,7 @@ export const anonymizeController = function (state, http, html, params, location
|
|||||||
try {
|
try {
|
||||||
resetValidity();
|
resetValidity();
|
||||||
state.gistOAuthRequired = false;
|
state.gistOAuthRequired = false;
|
||||||
if (state.githubConnections?.oauthConnected === false) {
|
state.gistAppRequired = false;
|
||||||
state.gistOAuthRequired = true;
|
|
||||||
setValidity("sourceUrl", "missing", false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const res = await http.get(`/api/gist/source/${o.gistId}`);
|
const res = await http.get(`/api/gist/source/${o.gistId}`);
|
||||||
if (!isCurrentSource(request)) return;
|
if (!isCurrentSource(request)) return;
|
||||||
state.details = res.data;
|
state.details = res.data;
|
||||||
@@ -1783,6 +1785,11 @@ export const anonymizeController = function (state, http, html, params, location
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (!isCurrentSource(request)) return;
|
if (!isCurrentSource(request)) return;
|
||||||
|
if (error.data?.error === "github_app_reconnect_required") {
|
||||||
|
state.gistAppRequired = true;
|
||||||
|
setValidity("sourceUrl", "missing", false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (error.data?.error === "github_oauth_required") {
|
if (error.data?.error === "github_oauth_required") {
|
||||||
state.gistOAuthRequired = true;
|
state.gistOAuthRequired = true;
|
||||||
setValidity("sourceUrl", "missing", false);
|
setValidity("sourceUrl", "missing", false);
|
||||||
|
|||||||
Vendored
+10
-10
@@ -1,15 +1,15 @@
|
|||||||
"use strict";(()=>{var xl=Object.defineProperty;var ed=(e,t)=>{for(var n in t)xl(e,n,{get:t[n],enumerable:!0})};var me=["abap","abc","actionscript","ada","alda","apache_conf","apex","applescript","aql","asciidoc","asl","assembly_x86","autohotkey","batchfile","c9search","c_cpp","cirru","clojure","cobol","coffee","coldfusion","crystal","csharp","csound_document","csound_orchestra","csound_score","csp","css","curly","d","dart","diff","django","dockerfile","dot","drools","edifact","eiffel","ejs","elixir","elm","erlang","forth","fortran","fsharp","fsl","ftl","gcode","gherkin","gitignore","glsl","gobstones","golang","graphqlschema","groovy","haml","handlebars","haskell","haskell_cabal","haxe","hjson","html","html_elixir","html_ruby","ini","io","jack","jade","java","javascript","json","json5","jsoniq","jsp","jssm","jsx","julia","kotlin","latex","less","liquid","lisp","livescript","logiql","logtalk","lsl","lua","luapage","lucene","makefile","markdown","mask","matlab","maze","mediawiki","mel","mixal","mushcode","mysql","nginx","nim","nix","nsis","nunjucks","objectivec","ocaml","pascal","perl","perl6","pgsql","php","php_laravel_blade","pig","plain_text","powershell","praat","prisma","prolog","properties","protobuf","puppet","python","qml","r","razor","rdoc","red","redshift","rhtml","rst","ruby","rust","sass","scad","scala","scheme","scss","sh","sjs","slim","smarty","snippets","soy_template","space","sparql","sql","sqlserver","stylus","svg","swift","tcl","terraform","tex","text","textile","toml","tsx","turtle","twig","typescript","vala","vbscript","velocity","verilog","vhdl","visualforce","wollok","xml","xquery","yaml","zeek"];var ve={notebook:"/script/notebook.c3144c18ae.min.js",org:"/script/org.f61f262915.min.js",pdf:"/script/pdf.4d9cc6ff49.min.js",markdown:"/script/markdown.44f2e93820.min.js",editor:"/script/editor.4f142d3adc.min.js"};var us=new Map,sd=ve;function Jt(e){if(!us.has(e)){let t=document.createElement("script");t.src=sd[e];let n=new Promise((r,s)=>{t.onload=r,t.onerror=()=>{us.delete(e),t.remove(),s(new Error(`Unable to load ${e}. Please retry.`))}});us.set(e,n),document.head.appendChild(t)}return us.get(e)}async function lr(){await Jt("editor"),ace.config.set("basePath","/script/external/ace/")}function po(e){let t=Object.create(null);for(let n of e.split(","))t[n]=1;return n=>n in t}var Pe={},Qt=[],at=()=>{},sn=()=>!1,fo=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&(e.charCodeAt(2)>122||e.charCodeAt(2)<97),ho=e=>e.startsWith("onUpdate:"),Ge=Object.assign,Oo=(e,t)=>{let n=e.indexOf(t);n>-1&&e.splice(n,1)},nd=Object.prototype.hasOwnProperty,De=(e,t)=>nd.call(e,t),be=Array.isArray,$t=e=>Io(e)==="[object Map]",co=e=>Io(e)==="[object Set]",dr=e=>Io(e)==="[object Date]";var we=e=>typeof e=="function",ze=e=>typeof e=="string",ht=e=>typeof e=="symbol",Te=e=>e!==null&&typeof e=="object",nn=e=>(Te(e)||we(e))&&we(e.then)&&we(e.catch),pr=Object.prototype.toString,Io=e=>pr.call(e),rn=e=>Io(e).slice(8,-1),cs=e=>Io(e)==="[object Object]",ps=e=>ze(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,mo=po(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted");var fs=e=>{let t=Object.create(null);return(n=>t[n]||(t[n]=e(n)))},rd=/-\w/g,Je=fs(e=>e.replace(rd,t=>t.slice(1).toUpperCase())),id=/\B([A-Z])/g,St=fs(e=>e.replace(id,"-$1").toLowerCase()),Xt=fs(e=>e.charAt(0).toUpperCase()+e.slice(1)),Po=fs(e=>e?`on${Xt(e)}`:""),gt=(e,t)=>!Object.is(e,t),vo=(e,...t)=>{for(let n=0;n<e.length;n++)e[n](...t)},hs=(e,t,n,r=!1)=>{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,writable:r,value:n})},Vo=e=>{let t=parseFloat(e);return isNaN(t)?e:t};var ur,qo=()=>ur||(ur=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function Me(e){if(be(e)){let t={};for(let n=0;n<e.length;n++){let r=e[n],s=ze(r)?ud(r):Me(r);if(s)for(let i in s)t[i]=s[i]}return t}else if(ze(e)||Te(e))return e}var ad=/;(?![^(]*\))/g,ld=/:([^]+)/,dd=/\/\*[^]*?\*\//g;function ud(e){let t={};return e.replace(dd,"").split(ad).forEach(n=>{if(n){let r=n.split(ld);r.length>1&&(t[r[0].trim()]=r[1].trim())}}),t}function A(e){let t="";if(ze(e))t=e;else if(be(e))for(let n=0;n<e.length;n++){let r=A(e[n]);r&&(t+=r+" ")}else if(Te(e))for(let n in e)e[n]&&(t+=n+" ");return t.trim()}var fr="itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly",hr=po(fr),cd=po(fr+",async,autofocus,autoplay,controls,default,defer,disabled,inert,loop,open,required,reversed,scoped,seamless,checked,muted,multiple,selected");function ms(e){return!!e||e===""}function pd(e,t){if(e.length!==t.length)return!1;let n=!0;for(let r=0;n&&r<e.length;r++)n=go(e[r],t[r]);return n}function cr(e,t){if(e.size!==t.size)return!1;let n=Array.from(t),r=new Uint8Array(n.length);for(let s of e){let i=-1;for(let a=0;a<n.length;a++)if(!r[a]&&go(s,n[a])){i=a;break}if(i<0)return!1;r[i]=1}return!0}function go(e,t){if(e===t)return!0;let n=dr(e),r=dr(t);if(n||r)returLine truncated
|
"use strict";(()=>{var xl=Object.defineProperty;var ed=(e,t)=>{for(var n in t)xl(e,n,{get:t[n],enumerable:!0})};var me=["abap","abc","actionscript","ada","alda","apache_conf","apex","applescript","aql","asciidoc","asl","assembly_x86","autohotkey","batchfile","c9search","c_cpp","cirru","clojure","cobol","coffee","coldfusion","crystal","csharp","csound_document","csound_orchestra","csound_score","csp","css","curly","d","dart","diff","django","dockerfile","dot","drools","edifact","eiffel","ejs","elixir","elm","erlang","forth","fortran","fsharp","fsl","ftl","gcode","gherkin","gitignore","glsl","gobstones","golang","graphqlschema","groovy","haml","handlebars","haskell","haskell_cabal","haxe","hjson","html","html_elixir","html_ruby","ini","io","jack","jade","java","javascript","json","json5","jsoniq","jsp","jssm","jsx","julia","kotlin","latex","less","liquid","lisp","livescript","logiql","logtalk","lsl","lua","luapage","lucene","makefile","markdown","mask","matlab","maze","mediawiki","mel","mixal","mushcode","mysql","nginx","nim","nix","nsis","nunjucks","objectivec","ocaml","pascal","perl","perl6","pgsql","php","php_laravel_blade","pig","plain_text","powershell","praat","prisma","prolog","properties","protobuf","puppet","python","qml","r","razor","rdoc","red","redshift","rhtml","rst","ruby","rust","sass","scad","scala","scheme","scss","sh","sjs","slim","smarty","snippets","soy_template","space","sparql","sql","sqlserver","stylus","svg","swift","tcl","terraform","tex","text","textile","toml","tsx","turtle","twig","typescript","vala","vbscript","velocity","verilog","vhdl","visualforce","wollok","xml","xquery","yaml","zeek"];var ve={notebook:"/script/notebook.c3144c18ae.min.js",org:"/script/org.f61f262915.min.js",markdown:"/script/markdown.44f2e93820.min.js",editor:"/script/editor.4f142d3adc.min.js",pdf:"/script/pdf.4d9cc6ff49.min.js"};var us=new Map,sd=ve;function Jt(e){if(!us.has(e)){let t=document.createElement("script");t.src=sd[e];let n=new Promise((r,s)=>{t.onload=r,t.onerror=()=>{us.delete(e),t.remove(),s(new Error(`Unable to load ${e}. Please retry.`))}});us.set(e,n),document.head.appendChild(t)}return us.get(e)}async function lr(){await Jt("editor"),ace.config.set("basePath","/script/external/ace/")}function po(e){let t=Object.create(null);for(let n of e.split(","))t[n]=1;return n=>n in t}var Pe={},Qt=[],at=()=>{},sn=()=>!1,fo=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&(e.charCodeAt(2)>122||e.charCodeAt(2)<97),ho=e=>e.startsWith("onUpdate:"),Ge=Object.assign,Oo=(e,t)=>{let n=e.indexOf(t);n>-1&&e.splice(n,1)},nd=Object.prototype.hasOwnProperty,De=(e,t)=>nd.call(e,t),be=Array.isArray,$t=e=>Io(e)==="[object Map]",co=e=>Io(e)==="[object Set]",dr=e=>Io(e)==="[object Date]";var we=e=>typeof e=="function",ze=e=>typeof e=="string",ht=e=>typeof e=="symbol",Te=e=>e!==null&&typeof e=="object",nn=e=>(Te(e)||we(e))&&we(e.then)&&we(e.catch),pr=Object.prototype.toString,Io=e=>pr.call(e),rn=e=>Io(e).slice(8,-1),cs=e=>Io(e)==="[object Object]",ps=e=>ze(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,mo=po(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted");var fs=e=>{let t=Object.create(null);return(n=>t[n]||(t[n]=e(n)))},rd=/-\w/g,Je=fs(e=>e.replace(rd,t=>t.slice(1).toUpperCase())),id=/\B([A-Z])/g,St=fs(e=>e.replace(id,"-$1").toLowerCase()),Xt=fs(e=>e.charAt(0).toUpperCase()+e.slice(1)),Po=fs(e=>e?`on${Xt(e)}`:""),gt=(e,t)=>!Object.is(e,t),vo=(e,...t)=>{for(let n=0;n<e.length;n++)e[n](...t)},hs=(e,t,n,r=!1)=>{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,writable:r,value:n})},Vo=e=>{let t=parseFloat(e);return isNaN(t)?e:t};var ur,qo=()=>ur||(ur=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function Me(e){if(be(e)){let t={};for(let n=0;n<e.length;n++){let r=e[n],s=ze(r)?ud(r):Me(r);if(s)for(let i in s)t[i]=s[i]}return t}else if(ze(e)||Te(e))return e}var ad=/;(?![^(]*\))/g,ld=/:([^]+)/,dd=/\/\*[^]*?\*\//g;function ud(e){let t={};return e.replace(dd,"").split(ad).forEach(n=>{if(n){let r=n.split(ld);r.length>1&&(t[r[0].trim()]=r[1].trim())}}),t}function A(e){let t="";if(ze(e))t=e;else if(be(e))for(let n=0;n<e.length;n++){let r=A(e[n]);r&&(t+=r+" ")}else if(Te(e))for(let n in e)e[n]&&(t+=n+" ");return t.trim()}var fr="itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly",hr=po(fr),cd=po(fr+",async,autofocus,autoplay,controls,default,defer,disabled,inert,loop,open,required,reversed,scoped,seamless,checked,muted,multiple,selected");function ms(e){return!!e||e===""}function pd(e,t){if(e.length!==t.length)return!1;let n=!0;for(let r=0;n&&r<e.length;r++)n=go(e[r],t[r]);return n}function cr(e,t){if(e.size!==t.size)return!1;let n=Array.from(t),r=new Uint8Array(n.length);for(let s of e){let i=-1;for(let a=0;a<n.length;a++)if(!r[a]&&go(s,n[a])){i=a;break}if(i<0)return!1;r[i]=1}return!0}function go(e,t){if(e===t)return!0;let n=dr(e),r=dr(t);if(n||r)returLine truncated
|
||||||
`))),e[js]=Bi(s);let i=r||s.props&&s.props.type==="number";So(e,t?"change":"input",a=>{a.target.composing||e[js](Fn(e.value,n,i))}),(n||i)&&So(e,"change",()=>{e.value=Fn(e.value,n,i)}),t||(So(e,"compositionstart",oc),So(e,"compositionend",Gi),So(e,"change",Gi))},mounted(e,{value:t,modifiers:{trim:n,number:r}}){let s=t??"",i=e[Bs];delete e[Bs],i!==void 0&&(e.type==="text"||e.type==="textarea")&&e.value!==i?e[js](Fn(e.value,n,r)):e.value=s},beforeUpdate(e,{value:t,oldValue:n,modifiers:{lazy:r,trim:s,number:i}},a){if(e[js]=Bi(a),e.composing)return;let u=(i||e.type==="number")&&!/^0\d/.test(e.value)?Vo(e.value):e.value,f=t??"";if(u===f)return;let m=e.getRootNode();(m instanceof Document||m instanceof ShadowRoot)&&m.activeElement===e&&e.type!=="range"&&(r&&t===n||s&&e.value.trim()===f)||(e.value=f)}};var sc=["ctrl","shift","alt","meta"],nc={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,t)=>sc.some(n=>e[`${n}Key`]&&!t.includes(n))},he=(e,t)=>{if(!e)return e;let n=e._withMods||(e._withMods={}),r=t.join(".");return n[r]||(n[r]=((s,...i)=>{for(let a=0;a<t.length;a++){let u=nc[t[a]];if(u&&u(s,t))return}return e(s,...i)}))},rc={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},No=(e,t)=>{let n=e._withKeys||(e._withKeys={}),r=t.join(".");return n[r]||(n[r]=(s=>{if(!("key"in s))return;let i=St(s.key);if(t.some(a=>a===i||rc[a]===i))return e(s)}))},ic=Ge({patchProp:xu},$u),Wi;function ac(){return Wi||(Wi=Ni(ic))}var Qi=((...e)=>{let t=ac().createApp(...e),{mount:n}=t;return t.mount=r=>{let s=dc(r);if(!s)return;let i=t._component;!we(i)&&!i.render&&!i.template&&(i.template=s.innerHTML),s.nodeType===1&&(s.textContent="");let a=n(s,!1,lc(s));return s instanceof Element&&(s.removeAttribute("v-cloak"),s.setAttribute("data-v-app","")),a},t});function lc(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function dc(e){return ze(e)?document.querySelector(e):e}var lo=typeof document<"u";function Zi(e){return typeof e=="object"||"displayName"in e||"props"in e||"__vccOpts"in e}function uc(e){return e.__esModule||e[Symbol.toStringTag]==="Module"||e.default&&Zi(e.default)}var Oe=Object.assign;function Ws(e,t){let n={};for(let r in t){let s=t[r];n[r]=wt(s)?s.map(e):e(s)}return n}var Ro=()=>{},wt=Array.isArray;function Bn(e,t){let n={};for(let r in e)n[r]=r in t?t[r]:e[r];return n}var xi=/#/g,cc=/&/g,pc=/\//g,fc=/=/g,hc=/\?/g,ea=/\+/g,mc=/%5B/g,vc=/%5D/g,ta=/%5E/g,gc=/%60/g,oa=/%7B/g,yc=/%7C/g,sa=/%7D/g,bc=/%20/g;function Gn(e){return e==null?"":encodeURI(""+e).replace(yc,"|").replace(mc,"[").replace(vc,"]")}function na(e){return Gn(e).replace(oa,"{").replace(sa,"}").replace(ta,"^")}function Hn(e){return Gn(e).replace(ea,"%2B").replace(bc,"+").replace(xi,"%23").replace(cc,"%26").replace(gc,"`").replace(oa,"{").replace(sa,"}").replace(ta,"^")}function wc(e){return Hn(e).replace(fc,"%3D")}function kc(e){return Gn(e).replace(xi,"%23").replace(hc,"%3F")}function ra(e){return kc(e).replace(pc,"%2F")}function Do(e){if(e==null)return null;try{return decodeURIComponent(""+e)}catch{}return""+e}var Ec=/\/$/,Cc=e=>e.replace(Ec,"");function Ks(e,t,n="/"){let r,s={},i="",a="",u=t.indexOf("#"),f=t.indexOf("?");return f=u>=0&&f>u?-1:f,f>=0&&(r=t.slice(0,f),i=t.slice(f,u>0?u:t.length),s=e(i.slice(1))),u>=0&&(r=r||t.slice(0,u),a=t.slice(u,t.length)),r=Sc(r??t,n),{fullPath:r+i+a,path:r,query:s,hash:Do(a)}}function ia(e,t){let n=t.query?e(t.query):"";return t.path+(n&&"?")+n+(t.hash||"")}function Wn(e,t){return!t||!e.toLowerCase().startsWith(t.toLowerCase())?e:e.slice(t.length)||"/"}function aa(e,t,n){let r=t.matched.length-1,s=n.matched.length-1;return r>-1&&r===s&&io(t.matched[r],n.matched[s])&&Kn(t.params,n.params)&&e(t.query)===e(n.query)&&t.hash===n.hash}function io(e,t){return(e.aliasOf||e)===(t.aliasOf||t)}function Kn(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!1;for(var n in e)if(!_c(e[n],t[n]))return!1;return!0}function _c(e,t){return wt(e)?Xi(e,t):wt(t)?Xi(t,e):e?.valueOf()===t?.valueOf()}function Xi(e,t){return wt(t)?e.length===t.length&&e.every((n,r)=>n===t[r]):e.length===1&&e[0]===t}function Sc(e,t){if(e.startsWith("/"))return e;if(!e)return t;let n=t.split("/"),r=e.split("/"),s=r[r.length-1];(s===".."||s===".")&&r.push("");let i=n.length-1,a,u;for(a=0;a<r.length;a++)if(u=r[a],u!==".")if(u==="..")i>1&&i--;else break;return n.slice(0,i).join("/")+"/"+r.slice(a).join("/")}var Wt={path:"/",name:void 0,params:{},query:{},hash:"",fullPath:"/",matched:[],meta:{},redirectedFrom:void 0},Ys=(function(e){return e.pop="pop",e.push="push",e})({}),Js=(function(e){return e.back="back",e.forward="forward",e.unknown="",e})({});function la(e){if(!e)if(lo){let t=document.querLine truncated
|
`))),e[js]=Bi(s);let i=r||s.props&&s.props.type==="number";So(e,t?"change":"input",a=>{a.target.composing||e[js](Fn(e.value,n,i))}),(n||i)&&So(e,"change",()=>{e.value=Fn(e.value,n,i)}),t||(So(e,"compositionstart",oc),So(e,"compositionend",Gi),So(e,"change",Gi))},mounted(e,{value:t,modifiers:{trim:n,number:r}}){let s=t??"",i=e[Bs];delete e[Bs],i!==void 0&&(e.type==="text"||e.type==="textarea")&&e.value!==i?e[js](Fn(e.value,n,r)):e.value=s},beforeUpdate(e,{value:t,oldValue:n,modifiers:{lazy:r,trim:s,number:i}},a){if(e[js]=Bi(a),e.composing)return;let u=(i||e.type==="number")&&!/^0\d/.test(e.value)?Vo(e.value):e.value,f=t??"";if(u===f)return;let m=e.getRootNode();(m instanceof Document||m instanceof ShadowRoot)&&m.activeElement===e&&e.type!=="range"&&(r&&t===n||s&&e.value.trim()===f)||(e.value=f)}};var sc=["ctrl","shift","alt","meta"],nc={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,t)=>sc.some(n=>e[`${n}Key`]&&!t.includes(n))},he=(e,t)=>{if(!e)return e;let n=e._withMods||(e._withMods={}),r=t.join(".");return n[r]||(n[r]=((s,...i)=>{for(let a=0;a<t.length;a++){let u=nc[t[a]];if(u&&u(s,t))return}return e(s,...i)}))},rc={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},No=(e,t)=>{let n=e._withKeys||(e._withKeys={}),r=t.join(".");return n[r]||(n[r]=(s=>{if(!("key"in s))return;let i=St(s.key);if(t.some(a=>a===i||rc[a]===i))return e(s)}))},ic=Ge({patchProp:xu},$u),Wi;function ac(){return Wi||(Wi=Ni(ic))}var Qi=((...e)=>{let t=ac().createApp(...e),{mount:n}=t;return t.mount=r=>{let s=dc(r);if(!s)return;let i=t._component;!we(i)&&!i.render&&!i.template&&(i.template=s.innerHTML),s.nodeType===1&&(s.textContent="");let a=n(s,!1,lc(s));return s instanceof Element&&(s.removeAttribute("v-cloak"),s.setAttribute("data-v-app","")),a},t});function lc(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function dc(e){return ze(e)?document.querySelector(e):e}var lo=typeof document<"u";function Zi(e){return typeof e=="object"||"displayName"in e||"props"in e||"__vccOpts"in e}function uc(e){return e.__esModule||e[Symbol.toStringTag]==="Module"||e.default&&Zi(e.default)}var Oe=Object.assign;function Ws(e,t){let n={};for(let r in t){let s=t[r];n[r]=wt(s)?s.map(e):e(s)}return n}var Ro=()=>{},wt=Array.isArray;function Bn(e,t){let n={};for(let r in e)n[r]=r in t?t[r]:e[r];return n}var xi=/#/g,cc=/&/g,pc=/\//g,fc=/=/g,hc=/\?/g,ea=/\+/g,mc=/%5B/g,vc=/%5D/g,ta=/%5E/g,gc=/%60/g,oa=/%7B/g,yc=/%7C/g,sa=/%7D/g,bc=/%20/g;function Gn(e){return e==null?"":encodeURI(""+e).replace(yc,"|").replace(mc,"[").replace(vc,"]")}function na(e){return Gn(e).replace(oa,"{").replace(sa,"}").replace(ta,"^")}function Hn(e){return Gn(e).replace(ea,"%2B").replace(bc,"+").replace(xi,"%23").replace(cc,"%26").replace(gc,"`").replace(oa,"{").replace(sa,"}").replace(ta,"^")}function wc(e){return Hn(e).replace(fc,"%3D")}function kc(e){return Gn(e).replace(xi,"%23").replace(hc,"%3F")}function ra(e){return kc(e).replace(pc,"%2F")}function Do(e){if(e==null)return null;try{return decodeURIComponent(""+e)}catch{}return""+e}var Ec=/\/$/,Cc=e=>e.replace(Ec,"");function Ks(e,t,n="/"){let r,s={},i="",a="",u=t.indexOf("#"),f=t.indexOf("?");return f=u>=0&&f>u?-1:f,f>=0&&(r=t.slice(0,f),i=t.slice(f,u>0?u:t.length),s=e(i.slice(1))),u>=0&&(r=r||t.slice(0,u),a=t.slice(u,t.length)),r=Sc(r??t,n),{fullPath:r+i+a,path:r,query:s,hash:Do(a)}}function ia(e,t){let n=t.query?e(t.query):"";return t.path+(n&&"?")+n+(t.hash||"")}function Wn(e,t){return!t||!e.toLowerCase().startsWith(t.toLowerCase())?e:e.slice(t.length)||"/"}function aa(e,t,n){let r=t.matched.length-1,s=n.matched.length-1;return r>-1&&r===s&&io(t.matched[r],n.matched[s])&&Kn(t.params,n.params)&&e(t.query)===e(n.query)&&t.hash===n.hash}function io(e,t){return(e.aliasOf||e)===(t.aliasOf||t)}function Kn(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!1;for(var n in e)if(!_c(e[n],t[n]))return!1;return!0}function _c(e,t){return wt(e)?Xi(e,t):wt(t)?Xi(t,e):e?.valueOf()===t?.valueOf()}function Xi(e,t){return wt(t)?e.length===t.length&&e.every((n,r)=>n===t[r]):e.length===1&&e[0]===t}function Sc(e,t){if(e.startsWith("/"))return e;if(!e)return t;let n=t.split("/"),r=e.split("/"),s=r[r.length-1];(s===".."||s===".")&&r.push("");let i=n.length-1,a,u;for(a=0;a<r.length;a++)if(u=r[a],u!==".")if(u==="..")i>1&&i--;else break;return n.slice(0,i).join("/")+"/"+r.slice(a).join("/")}var Wt={path:"/",name:void 0,params:{},query:{},hash:"",fullPath:"/",matched:[],meta:{},redirectedFrom:void 0},Ys=(function(e){return e.pop="pop",e.push="push",e})({}),Js=(function(e){return e.back="back",e.forward="forward",e.unknown="",e})({});function la(e){if(!e)if(lo){let t=document.querLine truncated
|
||||||
${JSON.stringify(e)}${t?`
|
${JSON.stringify(e)}${t?`
|
||||||
while being at
|
while being at
|
||||||
`+JSON.stringify(t):""}`},[Be.NAVIGATION_GUARD_REDIRECT]({from:e,to:t}){return`Redirected from "${e.fullPath}" to "${Ac(t)}" via a navigation guard.`},[Be.NAVIGATION_ABORTED]({from:e,to:t}){return`Navigation aborted from "${e.fullPath}" to "${t.fullPath}" via a navigation guard.`},[Be.NAVIGATION_CANCELLED]({from:e,to:t}){return`Navigation cancelled from "${e.fullPath}" to "${t.fullPath}" with a new navigation.`},[Be.NAVIGATION_DUPLICATED]({from:e,to:t}){return`Avoided redundant navigation to current location: "${e.fullPath}".`}};function ao(e,t){return Oe(new Error,{type:e,[fa]:!0},t)}function Mt(e,t){return e instanceof Error&&fa in e&&(t==null||!!(e.type&t))}var Tc=["params","query","hash"];function Ac(e){if(typeof e=="string")return e;if(e.path!=null)return e.path;let t={};for(let n of Tc)n in e&&(t[n]=e[n]);return JSON.stringify(t,null,2)}function ha(e){let t={};if(e===""||e==="?")return t;let n=(e[0]==="?"?e.slice(1):e).split("&");for(let r=0;r<n.length;++r){let s=n[r].replace(ea," "),i=s.indexOf("="),a=Do(i<0?s:s.slice(0,i)),u=i<0?null:Do(s.slice(i+1));if(a in t){let f=t[a];wt(f)||(f=t[a]=[f]),f.push(u)}else t[a]=u}return t}function Qn(e){let t="";for(let n in e){let r=e[n];if(n=wc(n),r==null){r!==void 0&&(t+=(t.length?"&":"")+n);continue}(wt(r)?r.map(s=>s&&Hn(s)):[r&&Hn(r)]).forEach(s=>{s!==void 0&&(t+=(t.length?"&":"")+n,s!=null&&(t+="="+s))})}return t}function ma(e){let t={};for(let n in e){let r=e[n];r!==void 0&&(t[n]=wt(r)?r.map(s=>s==null?null:""+s):r==null?r:""+r)}return t}var va=Symbol(""),Xn=Symbol(""),Qs=Symbol(""),Xs=Symbol(""),Zs=Symbol("");function To(){let e=[];function t(r){return e.push(r),()=>{let s=e.indexOf(r);s>-1&&e.splice(s,1)}}function n(){e=[]}return{add:t,list:()=>e.slice(),reset:n}}function Gt(e,t,n,r,s,i=a=>a()){let a=r&&(r.enterCallbacks[s]=r.enterCallbacks[s]||[]);return()=>new Promise((u,f)=>{let m=h=>{h===!1?f(ao(Be.NAVIGATION_ABORTED,{from:n,to:t})):h instanceof Error?f(h):Rc(h)?f(ao(Be.NAVIGATION_GUARD_REDIRECT,{from:t,to:h})):(a&&r.enterCallbacks[s]===a&&typeof h=="function"&&a.push(h),u())},g=i(()=>e.call(r&&r.instances[s],t,n,m)),w=Promise.resolve(g);e.length<3&&(w=w.then(m)),w.catch(h=>f(h))})}function xs(e,t,n,r,s=i=>i()){let i=[];for(let a of e)for(let u in a.components){let f=a.components[u];if(!(t!=="beforeRouteEnter"&&!a.instances[u]))if(Zi(f)){let m=(f.__vccOpts||f)[t];m&&i.push(Gt(m,n,r,a,u,s))}else{let m=f();i.push(()=>m.then(g=>{if(!g)throw new Error(`Couldn't resolve component "${u}" at "${a.path}"`);let w=uc(g)?g.default:g;a.mods[u]=g,a.components[u]=w;let h=(w.__vccOpts||w)[t];return h&&Gt(h,n,r,a,u,s)()}))}}return i}function ga(e,t){let n=[],r=[],s=[],i=Math.max(t.matched.length,e.matched.length);for(let a=0;a<i;a++){let u=t.matched[a];u&&(e.matched.find(m=>io(m,u))?r.push(u):n.push(u));let f=e.matched[a];f&&(t.matched.find(m=>io(m,f))||s.push(f))}return[n,r,s]}var Oc=()=>location.protocol+"//"+location.host;function Ra(e,t){let{pathname:n,search:r,hash:s}=t,i=e.indexOf("#");if(i>-1){let a=s.includes(e.slice(i))?e.slice(i).length:1,u=s.slice(a);return u[0]!=="/"&&(u="/"+u),Wn(u,"")}return Wn(n,e)+r+s}function Ic(e,t,n,r){let s=[],i=[],a=null,u=({state:h})=>{let b=Ra(e,location),E=n.value,k=t.value,R=0;if(h){if(n.value=b,t.value=h,a&&a===E){a=null;return}R=k?h.position-k.position:0}else r(b);s.forEach(D=>{D(n.value,E,{delta:R,type:Ys.pop,direction:R?R>0?Js.forward:Js.back:Js.unknown})})};function f(){a=n.value}function m(h){s.push(h);let b=()=>{let E=s.indexOf(h);E>-1&&s.splice(E,1)};return i.push(b),b}function g(){if(document.visibilityState==="hidden"){let{history:h}=window;if(!h.state)return;h.replaceState(Oe({},h.state,{scroll:ds()}),"")}}function w(){for(let h of i)h();i=[],window.removeEventListener("popstate",u),window.removeEventListener("pagehide",g),document.removeEventListener("visibilitychange",g)}return window.addEventListener("popstate",u),window.addEventListener("pagehide",g),document.addEventListener("visibilitychange",g),{pauseListeners:f,listen:m,destroy:w}}function ya(e,t,n,r=!1,s=!1){return{back:e,current:t,forward:n,replaced:r,position:window.history.length,scroll:s?ds():null}}function Pc(e){let{history:t,location:n}=window,r={value:Ra(e,n)},s={value:t.state};s.value||i(r.value,{back:null,current:r.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0);function i(f,m,g){let w=e.indexOf("#"),h=w>-1?(n.host&&document.querySelector("base")?e:e.slice(w))+f:Oc()+e+f;try{t[g?"replaceState":"pushState"](m,"",h),s.value=m}catch(b){console.error(b),n[g?"replace":"assign"](h)}}function a(f,m){i(f,Oe({},t.state,ya(s.value.back,f,s.value.forward,!0),m,{position:s.value.position}),!0),r.value=f}function u(f,m){let g=Oe({},s.value,t.state,{forward:f,scroll:ds()});i(g.current,g,!0),i(f,Oe({},ya(r.value,f,null),{position:g.position+1},m),!1),r.value=f}return{location:r,state:s,push:u,replace:a}}function Ta(e){e=la(e);let t=Pc(e),n=Ic(e,t.state,t.location,t.replace);function r(i,a=!0){a||n.pauseListeners(),history.go(i)}let s=Oe({locatLine truncated
|
`+JSON.stringify(t):""}`},[Be.NAVIGATION_GUARD_REDIRECT]({from:e,to:t}){return`Redirected from "${e.fullPath}" to "${Ac(t)}" via a navigation guard.`},[Be.NAVIGATION_ABORTED]({from:e,to:t}){return`Navigation aborted from "${e.fullPath}" to "${t.fullPath}" via a navigation guard.`},[Be.NAVIGATION_CANCELLED]({from:e,to:t}){return`Navigation cancelled from "${e.fullPath}" to "${t.fullPath}" with a new navigation.`},[Be.NAVIGATION_DUPLICATED]({from:e,to:t}){return`Avoided redundant navigation to current location: "${e.fullPath}".`}};function ao(e,t){return Oe(new Error,{type:e,[fa]:!0},t)}function Mt(e,t){return e instanceof Error&&fa in e&&(t==null||!!(e.type&t))}var Tc=["params","query","hash"];function Ac(e){if(typeof e=="string")return e;if(e.path!=null)return e.path;let t={};for(let n of Tc)n in e&&(t[n]=e[n]);return JSON.stringify(t,null,2)}function ha(e){let t={};if(e===""||e==="?")return t;let n=(e[0]==="?"?e.slice(1):e).split("&");for(let r=0;r<n.length;++r){let s=n[r].replace(ea," "),i=s.indexOf("="),a=Do(i<0?s:s.slice(0,i)),u=i<0?null:Do(s.slice(i+1));if(a in t){let f=t[a];wt(f)||(f=t[a]=[f]),f.push(u)}else t[a]=u}return t}function Qn(e){let t="";for(let n in e){let r=e[n];if(n=wc(n),r==null){r!==void 0&&(t+=(t.length?"&":"")+n);continue}(wt(r)?r.map(s=>s&&Hn(s)):[r&&Hn(r)]).forEach(s=>{s!==void 0&&(t+=(t.length?"&":"")+n,s!=null&&(t+="="+s))})}return t}function ma(e){let t={};for(let n in e){let r=e[n];r!==void 0&&(t[n]=wt(r)?r.map(s=>s==null?null:""+s):r==null?r:""+r)}return t}var va=Symbol(""),Xn=Symbol(""),Qs=Symbol(""),Xs=Symbol(""),Zs=Symbol("");function To(){let e=[];function t(r){return e.push(r),()=>{let s=e.indexOf(r);s>-1&&e.splice(s,1)}}function n(){e=[]}return{add:t,list:()=>e.slice(),reset:n}}function Gt(e,t,n,r,s,i=a=>a()){let a=r&&(r.enterCallbacks[s]=r.enterCallbacks[s]||[]);return()=>new Promise((u,f)=>{let m=h=>{h===!1?f(ao(Be.NAVIGATION_ABORTED,{from:n,to:t})):h instanceof Error?f(h):Rc(h)?f(ao(Be.NAVIGATION_GUARD_REDIRECT,{from:t,to:h})):(a&&r.enterCallbacks[s]===a&&typeof h=="function"&&a.push(h),u())},g=i(()=>e.call(r&&r.instances[s],t,n,m)),w=Promise.resolve(g);e.length<3&&(w=w.then(m)),w.catch(h=>f(h))})}function xs(e,t,n,r,s=i=>i()){let i=[];for(let a of e)for(let u in a.components){let f=a.components[u];if(!(t!=="beforeRouteEnter"&&!a.instances[u]))if(Zi(f)){let m=(f.__vccOpts||f)[t];m&&i.push(Gt(m,n,r,a,u,s))}else{let m=f();i.push(()=>m.then(g=>{if(!g)throw new Error(`Couldn't resolve component "${u}" at "${a.path}"`);let w=uc(g)?g.default:g;a.mods[u]=g,a.components[u]=w;let h=(w.__vccOpts||w)[t];return h&&Gt(h,n,r,a,u,s)()}))}}return i}function ga(e,t){let n=[],r=[],s=[],i=Math.max(t.matched.length,e.matched.length);for(let a=0;a<i;a++){let u=t.matched[a];u&&(e.matched.find(m=>io(m,u))?r.push(u):n.push(u));let f=e.matched[a];f&&(t.matched.find(m=>io(m,f))||s.push(f))}return[n,r,s]}var Oc=()=>location.protocol+"//"+location.host;function Ra(e,t){let{pathname:n,search:r,hash:s}=t,i=e.indexOf("#");if(i>-1){let a=s.includes(e.slice(i))?e.slice(i).length:1,u=s.slice(a);return u[0]!=="/"&&(u="/"+u),Wn(u,"")}return Wn(n,e)+r+s}function Ic(e,t,n,r){let s=[],i=[],a=null,u=({state:h})=>{let b=Ra(e,location),E=n.value,k=t.value,R=0;if(h){if(n.value=b,t.value=h,a&&a===E){a=null;return}R=k?h.position-k.position:0}else r(b);s.forEach(D=>{D(n.value,E,{delta:R,type:Ys.pop,direction:R?R>0?Js.forward:Js.back:Js.unknown})})};function f(){a=n.value}function m(h){s.push(h);let b=()=>{let E=s.indexOf(h);E>-1&&s.splice(E,1)};return i.push(b),b}function g(){if(document.visibilityState==="hidden"){let{history:h}=window;if(!h.state)return;h.replaceState(Oe({},h.state,{scroll:ds()}),"")}}function w(){for(let h of i)h();i=[],window.removeEventListener("popstate",u),window.removeEventListener("pagehide",g),document.removeEventListener("visibilitychange",g)}return window.addEventListener("popstate",u),window.addEventListener("pagehide",g),document.addEventListener("visibilitychange",g),{pauseListeners:f,listen:m,destroy:w}}function ya(e,t,n,r=!1,s=!1){return{back:e,current:t,forward:n,replaced:r,position:window.history.length,scroll:s?ds():null}}function Pc(e){let{history:t,location:n}=window,r={value:Ra(e,n)},s={value:t.state};s.value||i(r.value,{back:null,current:r.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0);function i(f,m,g){let w=e.indexOf("#"),h=w>-1?(n.host&&document.querySelector("base")?e:e.slice(w))+f:Oc()+e+f;try{t[g?"replaceState":"pushState"](m,"",h),s.value=m}catch(b){console.error(b),n[g?"replace":"assign"](h)}}function a(f,m){i(f,Oe({},t.state,ya(s.value.back,f,s.value.forward,!0),m,{position:s.value.position}),!0),r.value=f}function u(f,m){let g=Oe({},s.value,t.state,{forward:f,scroll:ds()});i(g.current,g,!0),i(f,Oe({},ya(r.value,f,null),{position:g.position+1},m),!1),r.value=f}return{location:r,state:s,push:u,replace:a}}function Ta(e){e=la(e);let t=Pc(e),n=Ic(e,t.state,t.location,t.replace);function r(i,a=!0){a||n.pauseListeners(),history.go(i)}let s=Oe({locatLine truncated
|
||||||
`)),e.options=Object.assign({},e.options,m.options),i.restore()})}a();let u=null;e.saveDefault=f=>{if(f&&f.preventDefault&&f.preventDefault(),e.saving)return;let m=i.checkpoint(),g={terms:e.terms.split(`
|
`)),e.options=Object.assign({},e.options,m.options),i.restore()})}a();let u=null;e.saveDefault=f=>{if(f&&f.preventDefault&&f.preventDefault(),e.saving)return;let m=i.checkpoint(),g={terms:e.terms.split(`
|
||||||
`).map(w=>w.trim()).filter(w=>w.length>0),options:e.options};e.saving=!0,e.error=null,t.post("/api/user/default",g).then(()=>{i.accept(m),e.saving=!1,e.message=e.unsavedChanges?null:"Saved",u&&r.cancel(u),u=r(()=>{e.message=null},2500)},w=>{e.saving=!1;let b="ERRORS."+(w&&w.data&&w.data.error);n(b).then(E=>{e.error=E&&E!==b?E:"Unable to save your defaults. Please try again."},()=>{e.error="Unable to save your defaults. Please try again."})})},e.deleteAccount=()=>{confirm("Delete your account? All your anonymized repositories, gists, and pull requests will be removed, and your personal data will be erased. This cannot be undone.")&&(e.deletingAccount=!0,t.delete("/api/user").then(()=>{window.location.href="/"},()=>{e.deletingAccount=!1,e.deleteError="Unable to delete the account. Please try again."}))}},La=function(e,t,n){e.repoId=null,e.repoUrl=null,e.claim=()=>{t.post("/api/repo/claim",{repoId:e.repoId,repoUrl:e.repoUrl}).then(r=>{n.url("/dashboard")},r=>{e.error=r.data,e.claimForm.repoUrl.setValidity("not_found",!1),e.claimForm.repoId.setValidity("not_found",!1)})}},Ua=function(e,t,n,r,s){e.user&&!e.user.status&&n.url("/dashboard"),e.watch("user.status",()=>{e.user&&!e.user.status&&n.url("/dashboard")}),e.features=[{key:"anonymize",num:"01",eyebrow:"Anonymize",title:"Double-anonymous,",accent:"your rules.",text:"Choose what reviewers may see: links, images, PDFs, notebooks, GitHub Pages. Add your own terms, with regex if you need it, and pick the expiration date.",cta:"Start an anonymization",href:"/anonymize",url:"anonymous.4open.science/anonymize",img:"/imgs/anonymize.png",alt:"The anonymize form: source repository, terms to redact, options and a live README preview"},{key:"review",num:"02",eyebrow:"Review",title:"Reviewers browse",accent:"the real thing.",text:"Highlighted source code, rendered PDFs, images, and notebooks, in a familiar file explorer. GitHub Pages is also supported.",cta:"Open the example",href:"https://anonymous.4open.science/r/840c8c57-3c32-451e-bf12-0e20be300389/",target:"_self",url:"anonymous.4open.science/r/840c8c57-\u2026",img:"/imgs/explorer.png",alt:"The repository explorer with a file tree and a rendered README"},{key:"manage",num:"03",eyebrow:"Manage",title:"One dashboard,",accent:"until the decision.",text:"Monitor views, edit configuration, remove or update your repository. Program chairs can group submissions under a conference with one shared expiry.",cta:"Open the dashboard",href:"/dashboard",needsUser:!0,url:"anonymous.4open.science/dashboard",img:"/imgs/dashboard.png",alt:"The dashboard listing anonymized repositories with status, views and expiry"}],e.feature=e.features[0].key,e.selectFeature=function(u){e.feature=u},e.featureHref=function(u){return u.needsUser&&!e.user?"/signin":u.href},e.featureTarget=function(u){return u.needsUser&&!e.user?"_self":u.target||void 0},e.featureKeydown=function(u,f){let m={ArrowDown:1,ArrowRight:1,ArrowUp:-1,ArrowLeft:-1,Home:"first",End:"last"}[u.key];if(m===void 0)return;u.preventDefault();let g=e.features.length,w=m==="first"?0:m==="last"?g-1:(f+m+g)%g;e.feature=e.features[w].key,s(()=>{let h=r.document.getElementById("feature-tab-"+e.feature);h&&h.focus()})},e.cards=[{key:"repositories",total:0,label:"repositories anonymized"},{key:"users",total:0,label:"researchers"},{key:"pageViews",total:0,label:"page views"},{key:"pullRequests",total:0,label:"pull requests"}];function i(){t.get("/api/stat/").then(u=>{e.stat=u.data,e.cards[0].total=u.data.nbRepositories,e.cards[1].total=u.data.nbUsers,e.cards[2].total=u.data.nbPageViews,e.cards[3].total=u.data.nbPullRequests})}i();function a(u){let f={series:u,bars:[],viewW:100,deltaToday:0,pctChange:0,pctAbs:0,isUp:!0};if(!u||u.length<2)return f;let m=new Array(u.length-1);for(let k=1;k<u.length;k++)m[k-1]=u[k]-u[k-1];let g=m.length,w=Math.max.apply(null,m),h=Math.min.apply(null,m),b=Math.min(0,h),E=w-b||1;f.viewW=g*2,f.bars=new Array(g);for(let k=0;k<g;k++){let R=(m[k]-b)/E,D=Math.max(1.5,R*34);f.bars[k]={x:(k*2+.25).toFixed(2),y:(36-D).toFixed(2),w:"1.5",h:D.toFixed(2)}}if(f.deltaToday=m[g-1],g>=2){let k=m[g-2];k&&(f.pctChange=(f.deltaToday-k)/k*100)}return f.pctAbs=Math.round(Math.abs(f.pctChange)),f.isUp=f.pctChange>=0,f}e.history={repositories:a([]),users:a([]),pageViews:a([]),pullRequests:a([])},t.get("/api/stat/history?days=60").then(u=>{let f=u.data||[];e.history={repositories:a(f.map(m=>m.nbRepositories||0)),users:a(f.map(m=>m.nbUsers||0)),pageViews:a(f.map(m=>m.nbPageViews||0)),pullRequests:a(f.map(m=>m.nbPullRequests||0))}})},Fa=function(e,t,n,r,s,i){let a=ct();e.on("routeLeave",function(){$('[data-toggle="tooltip"]').tooltip("dispose")}),e.watch("user.status",()=>{e.user==null&&n.url("/")}),e.user==null&&n.url("/"),a.timeout(()=>{$('[data-toggle="tooltip"]').tooltip()},250),e.quotaExpanded=!1,e.closeQuota=()=>{e.quotaExpanded=!1,rt(()=>document.querySelector(".dashboard-quota > summary")?.focus())},Kt()(document,"click",C=>{e.quotaExpanded&&!C.target.closest?.(".dashboard-quota")&&
Line truncated
|
`).map(w=>w.trim()).filter(w=>w.length>0),options:e.options};e.saving=!0,e.error=null,t.post("/api/user/default",g).then(()=>{i.accept(m),e.saving=!1,e.message=e.unsavedChanges?null:"Saved",u&&r.cancel(u),u=r(()=>{e.message=null},2500)},w=>{e.saving=!1;let b="ERRORS."+(w&&w.data&&w.data.error);n(b).then(E=>{e.error=E&&E!==b?E:"Unable to save your defaults. Please try again."},()=>{e.error="Unable to save your defaults. Please try again."})})},e.deleteAccount=()=>{confirm("Delete your account? All your anonymized repositories, gists, and pull requests will be removed, and your personal data will be erased. This cannot be undone.")&&(e.deletingAccount=!0,t.delete("/api/user").then(()=>{window.location.href="/"},()=>{e.deletingAccount=!1,e.deleteError="Unable to delete the account. Please try again."}))}},La=function(e,t,n){e.repoId=null,e.repoUrl=null,e.claim=()=>{t.post("/api/repo/claim",{repoId:e.repoId,repoUrl:e.repoUrl}).then(r=>{n.url("/dashboard")},r=>{e.error=r.data,e.claimForm.repoUrl.setValidity("not_found",!1),e.claimForm.repoId.setValidity("not_found",!1)})}},Ua=function(e,t,n,r,s){e.user&&!e.user.status&&n.url("/dashboard"),e.watch("user.status",()=>{e.user&&!e.user.status&&n.url("/dashboard")}),e.features=[{key:"anonymize",num:"01",eyebrow:"Anonymize",title:"Double-anonymous,",accent:"your rules.",text:"Choose what reviewers may see: links, images, PDFs, notebooks, GitHub Pages. Add your own terms, with regex if you need it, and pick the expiration date.",cta:"Start an anonymization",href:"/anonymize",url:"anonymous.4open.science/anonymize",img:"/imgs/anonymize.png",alt:"The anonymize form: source repository, terms to redact, options and a live README preview"},{key:"review",num:"02",eyebrow:"Review",title:"Reviewers browse",accent:"the real thing.",text:"Highlighted source code, rendered PDFs, images, and notebooks, in a familiar file explorer. GitHub Pages is also supported.",cta:"Open the example",href:"https://anonymous.4open.science/r/840c8c57-3c32-451e-bf12-0e20be300389/",target:"_self",url:"anonymous.4open.science/r/840c8c57-\u2026",img:"/imgs/explorer.png",alt:"The repository explorer with a file tree and a rendered README"},{key:"manage",num:"03",eyebrow:"Manage",title:"One dashboard,",accent:"until the decision.",text:"Monitor views, edit configuration, remove or update your repository. Program chairs can group submissions under a conference with one shared expiry.",cta:"Open the dashboard",href:"/dashboard",needsUser:!0,url:"anonymous.4open.science/dashboard",img:"/imgs/dashboard.png",alt:"The dashboard listing anonymized repositories with status, views and expiry"}],e.feature=e.features[0].key,e.selectFeature=function(u){e.feature=u},e.featureHref=function(u){return u.needsUser&&!e.user?"/signin":u.href},e.featureTarget=function(u){return u.needsUser&&!e.user?"_self":u.target||void 0},e.featureKeydown=function(u,f){let m={ArrowDown:1,ArrowRight:1,ArrowUp:-1,ArrowLeft:-1,Home:"first",End:"last"}[u.key];if(m===void 0)return;u.preventDefault();let g=e.features.length,w=m==="first"?0:m==="last"?g-1:(f+m+g)%g;e.feature=e.features[w].key,s(()=>{let h=r.document.getElementById("feature-tab-"+e.feature);h&&h.focus()})},e.cards=[{key:"repositories",total:0,label:"repositories anonymized"},{key:"users",total:0,label:"researchers"},{key:"pageViews",total:0,label:"page views"},{key:"pullRequests",total:0,label:"pull requests"}];function i(){t.get("/api/stat/").then(u=>{e.stat=u.data,e.cards[0].total=u.data.nbRepositories,e.cards[1].total=u.data.nbUsers,e.cards[2].total=u.data.nbPageViews,e.cards[3].total=u.data.nbPullRequests})}i();function a(u){let f={series:u,bars:[],viewW:100,deltaToday:0,pctChange:0,pctAbs:0,isUp:!0};if(!u||u.length<2)return f;let m=new Array(u.length-1);for(let k=1;k<u.length;k++)m[k-1]=u[k]-u[k-1];let g=m.length,w=Math.max.apply(null,m),h=Math.min.apply(null,m),b=Math.min(0,h),E=w-b||1;f.viewW=g*2,f.bars=new Array(g);for(let k=0;k<g;k++){let R=(m[k]-b)/E,D=Math.max(1.5,R*34);f.bars[k]={x:(k*2+.25).toFixed(2),y:(36-D).toFixed(2),w:"1.5",h:D.toFixed(2)}}if(f.deltaToday=m[g-1],g>=2){let k=m[g-2];k&&(f.pctChange=(f.deltaToday-k)/k*100)}return f.pctAbs=Math.round(Math.abs(f.pctChange)),f.isUp=f.pctChange>=0,f}e.history={repositories:a([]),users:a([]),pageViews:a([]),pullRequests:a([])},t.get("/api/stat/history?days=60").then(u=>{let f=u.data||[];e.history={repositories:a(f.map(m=>m.nbRepositories||0)),users:a(f.map(m=>m.nbUsers||0)),pageViews:a(f.map(m=>m.nbPageViews||0)),pullRequests:a(f.map(m=>m.nbPullRequests||0))}})},Fa=function(e,t,n,r,s,i){let a=ct();e.on("routeLeave",function(){$('[data-toggle="tooltip"]').tooltip("dispose")}),e.watch("user.status",()=>{e.user==null&&n.url("/")}),e.user==null&&n.url("/"),a.timeout(()=>{$('[data-toggle="tooltip"]').tooltip()},250),e.quotaExpanded=!1,e.closeQuota=()=>{e.quotaExpanded=!1,rt(()=>document.querySelector(".dashboard-quota > summary")?.focus())},Kt()(document,"click",C=>{e.quotaExpanded&&!C.target.closest?.(".dashboard-quota")&&
Line truncated
|
||||||
`)),e.options=Object.assign({},e.options,j.options),e.options.expirationDate=j.options&&j.options.expirationDate?new Date(j.options.expirationDate):T(),!r.repoId&&!r.pullRequestId&&!r.gistId&&!e.anonymize?.terms?.dirty&&(e.terms=e.defaultTerms),_&&_()})}function U(_,I,j){e.anonymize&&e.anonymize[_]&&e.anonymize[_].setValidity(I,j)}function ie(_){try{let I=parseGithubUrl(_);if(I&&I.owner&&I.repo)return I.owner+"/"+I.repo}catch{}return null}e.reconnectingSource=!1,e.reconnectRepositoryId=void 0,e.reconnectSource=async()=>{if(confirm("Reconnect to the repository currently at this GitHub URL? Review its branch and commit before saving. Saving will replace the published snapshot.")){e.reconnectingSource=!0,e.reconnectRepositoryId=void 0,e.source.commit="",e.source.branch="",e.readme="",e.branches=[];try{await G()}catch{}}};function re(){return e.reconnectingSource||!e.isUpdate||!e._originalRepositoryID?void 0:ie(e.sourceUrl)===e._originalFullName?e._originalRepositoryID:void 0}async function C(){e._preservingDraft=!0;try{await e.urlSelected(!0)}finally{e._preservingDraft=!1}}async function O(){let _;try{_=JSON.parse(sessionStorage.getItem("github-access-draft")||"null")}catch{return!1}if(!_||_.path!==s.path()||Date.now()-_.savedAt>=30*6e4)return R.restore()?(e.sourceUrl&&await C(),!0):!1;R.restore();for(let I of["sourceUrl","terms","repoId","pullRequestId","gistId","source","options","conference","githubConnection"])Object.prototype.hasOwnProperty.call(_.draft,I)&&(e[I]=_.draft[I]);return e.options.expirationDate&&(e.options.expirationDate=new Date(e.options.expirationDate)),await C(),sessionStorage.removeItem("github-access-draft"),!0}q(()=>{!r.repoId&&!r.pullRequestId&&!r.gistId&&a(O,0),r.repoId&&r.repoId!=""&&(e.isUpdate=!0,e.detectedType="repo",e.repoId=r.repoId,t.get("/api/repo/"+e.repoId).then(async _=>{e.githubConnection=_.data.connection||"oauth",e.sourceUrl="https://github.com/"+_.data.source.fullName,e._originalFullName=_.data.source.fullName,e.terms=_.data.options.terms.filter(I=>I).join(`
|
`)),e.options=Object.assign({},e.options,j.options),e.options.expirationDate=j.options&&j.options.expirationDate?new Date(j.options.expirationDate):T(),!r.repoId&&!r.pullRequestId&&!r.gistId&&!e.anonymize?.terms?.dirty&&(e.terms=e.defaultTerms),_&&_()})}function U(_,I,j){e.anonymize&&e.anonymize[_]&&e.anonymize[_].setValidity(I,j)}function ie(_){try{let I=parseGithubUrl(_);if(I&&I.owner&&I.repo)return I.owner+"/"+I.repo}catch{}return null}e.reconnectingSource=!1,e.reconnectRepositoryId=void 0,e.reconnectSource=async()=>{if(confirm("Reconnect to the repository currently at this GitHub URL? Review its branch and commit before saving. Saving will replace the published snapshot.")){e.reconnectingSource=!0,e.reconnectRepositoryId=void 0,e.source.commit="",e.source.branch="",e.readme="",e.branches=[];try{await G()}catch{}}};function re(){return e.reconnectingSource||!e.isUpdate||!e._originalRepositoryID?void 0:ie(e.sourceUrl)===e._originalFullName?e._originalRepositoryID:void 0}async function C(){e._preservingDraft=!0;try{await e.urlSelected(!0)}finally{e._preservingDraft=!1}}async function O(){let _;try{_=JSON.parse(sessionStorage.getItem("github-access-draft")||"null")}catch{return!1}if(!_||_.path!==s.path()||Date.now()-_.savedAt>=30*6e4)return R.restore()?(e.sourceUrl&&await C(),!0):!1;R.restore();for(let I of["sourceUrl","terms","repoId","pullRequestId","gistId","source","options","conference","githubConnection"])Object.prototype.hasOwnProperty.call(_.draft,I)&&(e[I]=_.draft[I]);return e.options.expirationDate&&(e.options.expirationDate=new Date(e.options.expirationDate)),await C(),sessionStorage.removeItem("github-access-draft"),!0}q(()=>{!r.repoId&&!r.pullRequestId&&!r.gistId&&a(O,0),r.repoId&&r.repoId!=""&&(e.isUpdate=!0,e.detectedType="repo",e.repoId=r.repoId,t.get("/api/repo/"+e.repoId).then(async _=>{e.githubConnection=_.data.connection||"oauth",e.sourceUrl="https://github.com/"+_.data.source.fullName,e._originalFullName=_.data.source.fullName,e.terms=_.data.options.terms.filter(I=>I).join(`
|
||||||
`),e.source=_.data.source,e.role=_.data.role||"owner",e.coauthors=_.data.coauthors||[],e._originalBranch=_.data.source.branch,e.options=Object.assign({},e.options,_.data.options),e.conference=_.data.conference,e._originalConference=_.data.conference,e.repositoryID=_.data.source.repositoryID,e._originalRepositoryID=_.data.source.repositoryID,_.data.options.expirationDate&&(e.options.expirationDate=new Date(_.data.options.expirationDate)),E=k(parseGithubUrl(e.sourceUrl)),!await O()&&(await Promise.all([G(),J()]),ue())},()=>{s.url("/404")})),r.pullRequestId&&r.pullRequestId!=""&&(e.isUpdate=!0,e.detectedType="pr",e.pullRequestId=r.pullRequestId,t.get("/api/pr/"+e.pullRequestId).then(async _=>{if(e.githubConnection=_.data.connection||"oauth",e.sourceUrl="https://github.com/"+_.data.source.repositoryFullName+"/pull/"+_.data.source.pullRequestId,e.terms=_.data.options.terms.filter(I=>I).join(`
|
`),e.source=_.data.source,e.role=_.data.role||"owner",e.coauthors=_.data.coauthors||[],e._originalBranch=_.data.source.branch,e.options=Object.assign({},e.options,_.data.options),e.conference=_.data.conference,e._originalConference=_.data.conference,e.repositoryID=_.data.source.repositoryID,e._originalRepositoryID=_.data.source.repositoryID,_.data.options.expirationDate&&(e.options.expirationDate=new Date(_.data.options.expirationDate)),E=k(parseGithubUrl(e.sourceUrl)),!await O()&&(await Promise.all([G(),J()]),ue())},()=>{s.url("/404")})),r.pullRequestId&&r.pullRequestId!=""&&(e.isUpdate=!0,e.detectedType="pr",e.pullRequestId=r.pullRequestId,t.get("/api/pr/"+e.pullRequestId).then(async _=>{if(e.githubConnection=_.data.connection||"oauth",e.sourceUrl="https://github.com/"+_.data.source.repositoryFullName+"/pull/"+_.data.source.pullRequestId,e.terms=_.data.options.terms.filter(I=>I).join(`
|
||||||
`),e.source=_.data.source,e.options=Object.assign({},e.options,_.data.options),e.conference=_.data.conference,e._originalConference=_.data.conference,_.data.options.expirationDate&&(e.options.expirationDate=new Date(_.data.options.expirationDate)),E=k(parseGithubUrl(e.sourceUrl)),!await O())try{await pe()}catch{}},()=>{s.url("/404")})),r.gistId&&r.gistId!=""&&(e.isUpdate=!0,e.detectedType="gist",e.gistId=r.gistId,t.get("/api/gist/"+e.gistId).then(async _=>{e.sourceUrl="https://gist.github.com/"+_.data.source.gistId,e.terms=_.data.options.terms.filter(I=>I).join(`
|
`),e.source=_.data.source,e.options=Object.assign({},e.options,_.data.options),e.conference=_.data.conference,e._originalConference=_.data.conference,_.data.options.expirationDate&&(e.options.expirationDate=new Date(_.data.options.expirationDate)),E=k(parseGithubUrl(e.sourceUrl)),!await O())try{await pe()}catch{}},()=>{s.url("/404")})),r.gistId&&r.gistId!=""&&(e.isUpdate=!0,e.detectedType="gist",e.gistId=r.gistId,t.get("/api/gist/"+e.gistId).then(async _=>{e.sourceUrl="https://gist.github.com/"+_.data.source.gistId,e.terms=_.data.options.terms.filter(I=>I).join(`
|
||||||
`),e.source=_.data.source,e.options=Object.assign({},e.options,_.data.options),e.conference=_.data.conference,e._originalConference=_.data.conference,_.data.options.expirationDate&&(e.options.expirationDate=new Date(_.data.options.expirationDate)),E=k(parseGithubUrl(e.sourceUrl)),!await O()&&await Ae()},()=>{s.url("/404")}))}),t.get("/github/connections").then(_=>{e.githubConnections=_.data,!r.repoId&&!r.pullRequestId&&!r.gistId&&e.githubConnection===void 0&&_.data.appEnabled&&_.data.appConnected&&(e.githubConnection="github-app",e.sourceUrl&&e.workspaceOpen&&C())}).catch(()=>{}),e.urlSelected=async(_=!1)=>{let I=++f,j;try{j=parseGithubUrl(e.sourceUrl.trim())}catch{e.sourceLoading=!1,oe.cancel(),_e.cancel(),Se.cancel(),e.previewStatus="idle",e.sourceUrlError=e.sourceUrl?"Please provide a valid GitHub URL.":"",U("sourceUrl","github",!1);return}let M=k(j),v=_||E===M;E=M,e.sourceUrlError="",U("sourceUrl","github",!0);let S=document.activeElement?.id==="sourceUrl-landing";e.workspaceOpen=!0,S&&a(()=>document.getElementById("sourceUrl")?.focus(),0),e.reconnectingSource=!1,e.reconnectRepositoryId=void 0,!v&&!e.isUpdate&&(e.repoId="",e.pullRequestId="",e.gistId=""),e.details=null,e.branches=[],v||(e.source={type:"GitHubStream",branch:"",commit:""}),oe.cancel(),_e.cancel(),Se.cancel(),le.clear(),Ee.clear(),e.previewStatus="idle",e.anonymize_readme="",e.readme="",e.html_readme="",e.detectedType=null,e.gistOAuthRequired=!1,e._preservingDraft=v;try{j.gistId&&!j.repo?(e.detectedType="gist",e.source={gistId:j.gistId},await Ae()):j.pullRequestId?(e.detectedType="pr",e.source={repositoryFullName:j.owner+"/"+j.repo,pullRequestId:j.pullRequestId},await pe()):(e.detectedType="repo",await Promise.all([G(),J()]),ue())}catch{}finally{I===f&&(e._preservingDraft=!1)}$('[data-toggle="tooltip"]').tooltip()},$('[data-toggle="tooltip"]').tooltip(),e.watch("source.branch",async()=>{if(e.detectedType!=="repo")return;let _=e.branches.filter(j=>j.name==e.source.branch)[0];if(!_)return;!(!e.reconnectingSource&&e.isUpdate&&e._originalBranch===e.source.branch&&!!e.source.commit)&&!(e._preservingDraft&&e.source.commit)&&(e.source.commit=_.commit),e.readme=_.readme,await J(),ue()}),e.getBranches=async _=>{let I=parseGithubUrl(e.sourceUrl),j=h();try{let M=await t.get(`/api/repo/${I.owner}/${I.repo}/branches`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&r.repoId&&ie(e.sourceUrl)===e._originalFullName?r.repoId:void 0,connection:e.githubConnection,force:_===!0||e.reconnectingSource?"1":"0",repositoryID:re()}});if(!w(j))return;e.branches=M.data,e.sourceUnreachable=!1,e.source.branch||(e.source.branch=e.details.defaultBranch);let v=e.branches.filter(S=>S.name==e.source.branch);v.length>0&&(!(!e.reconnectingSource&&!_&&e.isUpdate&&!e.options.update&&e._originalBranch===e.source.branch&&e.source.commit)&&!(e._preservingDraft&&e.source.commit)&&(e.source.commit=v[0].commit),e.readme=v[0].readme,await J(_))}catch(M){if(!w(j))return;e.branches=[],e.sourceUnreachable=M&&(M.status===404||M.data&&M.data.error==="repo_not_found");let v=M&&M.data&&M.data.error||(M&&M.status===404?"repo_not_found":"unknown_error");i("ERRORS."+v).then(S=>{e.toasts=e.toasts||[],e.addToast({title:"Error",date:new Date,body:S}),e.error=S},console.error),typeof U=="function"&&U("sourceUrl","missing",!1)}finally{b(j)}};async function G(){let _=parseGithubUrl(e.sourceUrl),I=h();try{z();let j=await t.get(`/api/repo/${_.owner}/${_.repo}/`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&r.repoId&&ie(e.sourceUrl)===e._originalFullName?r.repoId:void 0,connection:e.githubConnection,repositoryID:re(),force:"1"}});if(!w(I))return;e.details=j.data,e.reconnectingSource&&(e.reconnectRepositoryId=e.details.externalId),e.details&&e.details.id&&(e.repositoryID=e.details.id),e.repoId||(e.repoId=e.details.repo+"-"+generateRandomId(4)),await e.getBranches(e.reconnectingSource)}catch(j){if(!w(I))return;throw j.data&&(i("ERRORS."+j.data.error).then(M=>{e.addToast({title:"Error",date:new Date,body:M}),e.error=M},console.error),te(j.data.error)),U("sourceUrl","missing",!1),j}finally{b(I)}}async function J(_){if(e.readme&&!_)return e.readme;let I=parseGithubUrl(e.sourceUrl),j=h();try{let M=await t.get(`/api/repo/${I.owner}/${I.repo}/readme`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&r.repoId&&ie(e.sourceUrl)===e._originalFullName?r.repoId:void 0,connection:e.githubConnection,force:_===!0?"1":"0",branch:e.source.branch,repositoryID:re()}});w(j,!0)&&(e.readme=M.data)}catch{w(j,!0)&&(e.readme="")}finally{b(j)}}function ee(){let _={terms:e.terms?e.terms.split(`
|
`),e.source=_.data.source,e.options=Object.assign({},e.options,_.data.options),e.conference=_.data.conference,e._originalConference=_.data.conference,_.data.options.expirationDate&&(e.options.expirationDate=new Date(_.data.options.expirationDate)),E=k(parseGithubUrl(e.sourceUrl)),!await O()&&await Ae()},()=>{s.url("/404")}))}),t.get("/github/connections").then(_=>{e.githubConnections=_.data,!r.repoId&&!r.pullRequestId&&!r.gistId&&e.githubConnection===void 0&&_.data.appEnabled&&_.data.appConnected&&(e.githubConnection="github-app",e.sourceUrl&&e.workspaceOpen&&C())}).catch(()=>{}),e.urlSelected=async(_=!1)=>{let I=++f,j;try{j=parseGithubUrl(e.sourceUrl.trim())}catch{e.sourceLoading=!1,oe.cancel(),_e.cancel(),Se.cancel(),e.previewStatus="idle",e.sourceUrlError=e.sourceUrl?"Please provide a valid GitHub URL.":"",U("sourceUrl","github",!1);return}let M=k(j),v=_||E===M;E=M,e.sourceUrlError="",U("sourceUrl","github",!0);let S=document.activeElement?.id==="sourceUrl-landing";e.workspaceOpen=!0,S&&a(()=>document.getElementById("sourceUrl")?.focus(),0),e.reconnectingSource=!1,e.reconnectRepositoryId=void 0,!v&&!e.isUpdate&&(e.repoId="",e.pullRequestId="",e.gistId=""),e.details=null,e.branches=[],v||(e.source={type:"GitHubStream",branch:"",commit:""}),oe.cancel(),_e.cancel(),Se.cancel(),le.clear(),Ee.clear(),e.previewStatus="idle",e.anonymize_readme="",e.readme="",e.html_readme="",e.detectedType=null,e.gistOAuthRequired=!1,e.gistAppRequired=!1,e._preservingDraft=v;try{j.gistId&&!j.repo?(e.detectedType="gist",e.source={gistId:j.gistId},await Ae()):j.pullRequestId?(e.detectedType="pr",e.source={repositoryFullName:j.owner+"/"+j.repo,pullRequestId:j.pullRequestId},await pe()):(e.detectedType="repo",await Promise.all([G(),J()]),ue())}catch{}finally{I===f&&(e._preservingDraft=!1)}$('[data-toggle="tooltip"]').tooltip()},$('[data-toggle="tooltip"]').tooltip(),e.watch("source.branch",async()=>{if(e.detectedType!=="repo")return;let _=e.branches.filter(j=>j.name==e.source.branch)[0];if(!_)return;!(!e.reconnectingSource&&e.isUpdate&&e._originalBranch===e.source.branch&&!!e.source.commit)&&!(e._preservingDraft&&e.source.commit)&&(e.source.commit=_.commit),e.readme=_.readme,await J(),ue()}),e.getBranches=async _=>{let I=parseGithubUrl(e.sourceUrl),j=h();try{let M=await t.get(`/api/repo/${I.owner}/${I.repo}/branches`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&r.repoId&&ie(e.sourceUrl)===e._originalFullName?r.repoId:void 0,connection:e.githubConnection,force:_===!0||e.reconnectingSource?"1":"0",repositoryID:re()}});if(!w(j))return;e.branches=M.data,e.sourceUnreachable=!1,e.source.branch||(e.source.branch=e.details.defaultBranch);let v=e.branches.filter(S=>S.name==e.source.branch);v.length>0&&(!(!e.reconnectingSource&&!_&&e.isUpdate&&!e.options.update&&e._originalBranch===e.source.branch&&e.source.commit)&&!(e._preservingDraft&&e.source.commit)&&(e.source.commit=v[0].commit),e.readme=v[0].readme,await J(_))}catch(M){if(!w(j))return;e.branches=[],e.sourceUnreachable=M&&(M.status===404||M.data&&M.data.error==="repo_not_found");let v=M&&M.data&&M.data.error||(M&&M.status===404?"repo_not_found":"unknown_error");i("ERRORS."+v).then(S=>{e.toasts=e.toasts||[],e.addToast({title:"Error",date:new Date,body:S}),e.error=S},console.error),typeof U=="function"&&U("sourceUrl","missing",!1)}finally{b(j)}};async function G(){let _=parseGithubUrl(e.sourceUrl),I=h();try{z();let j=await t.get(`/api/repo/${_.owner}/${_.repo}/`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&r.repoId&&ie(e.sourceUrl)===e._originalFullName?r.repoId:void 0,connection:e.githubConnection,repositoryID:re(),force:"1"}});if(!w(I))return;e.details=j.data,e.reconnectingSource&&(e.reconnectRepositoryId=e.details.externalId),e.details&&e.details.id&&(e.repositoryID=e.details.id),e.repoId||(e.repoId=e.details.repo+"-"+generateRandomId(4)),await e.getBranches(e.reconnectingSource)}catch(j){if(!w(I))return;throw j.data&&(i("ERRORS."+j.data.error).then(M=>{e.addToast({title:"Error",date:new Date,body:M}),e.error=M},console.error),te(j.data.error)),U("sourceUrl","missing",!1),j}finally{b(I)}}async function J(_){if(e.readme&&!_)return e.readme;let I=parseGithubUrl(e.sourceUrl),j=h();try{let M=await t.get(`/api/repo/${I.owner}/${I.repo}/readme`,{params:{reconnect:e.reconnectingSource?"1":void 0,anonymizedRepoId:e.isUpdate&&r.repoId&&ie(e.sourceUrl)===e._originalFullName?r.repoId:void 0,connection:e.githubConnection,force:_===!0?"1":"0",branch:e.source.branch,repositoryID:re()}});w(j,!0)&&(e.readme=M.data)}catch{w(j,!0)&&(e.readme="")}finally{b(j)}}function ee(){let _={terms:e.terms?e.terms.split(`
|
||||||
`):[],image:!!e.options.image,link:!!e.options.link,repoId:e.repoId};e.source&&e.source.branch&&(_.branchName=e.source.branch);try{let I=parseGithubUrl(e.sourceUrl);_.repoName=`${I.owner}/${I.repo}`}catch{}return _}function Q(_,I,j){let M=null,v=0,S=()=>{if(e.detectedType!==_)return;M&&a.cancel(M);let V=++v;e.previewStatus="loading",M=a(()=>{M=null;let F=I();if(!F){e.previewStatus="idle";return}t.post("/api/anonymize-preview",F).then(B=>{V===v&&(j(B.data,F),e.previewStatus="ready")}).catch(()=>{V===v&&(e.previewStatus="error")})},200)};return S.cancel=()=>{v++,M&&a.cancel(M),M=null},e.on("dispose",S.cancel),S}e.retryPreview=()=>{e.detectedType==="repo"&&oe(),e.detectedType==="pr"&&_e(),e.detectedType==="gist"&&Se()};let oe=Q("repo",()=>e.readme?{content:e.readme,options:ee()}:null,_=>{if(typeof _?.content!="string")throw Error("Invalid preview response");e.anonymize_readme=_.content;let I="";try{let M=parseGithubUrl(e.sourceUrl),v=e.source.branch||e.details&&e.details.defaultBranch||"main";I=`https://github.com/${M.owner}/${M.repo}/raw/${v}/`}catch{}let j=renderMD(e.anonymize_readme,I);e.html_readme=j,a(Prism.highlightAll,150)});function ue(){!e.anonymize||!e.anonymize.terms||(e.termsRegexWarning=!!e.terms&&!!e.terms.match(/[-[\]{}()*+?.,\\^$|#]/g),oe())}async function pe(){let _=parseGithubUrl(e.sourceUrl),I=h();try{z();let j=await t.get(`/api/pr/${_.owner}/${_.repo}/${_.pullRequestId}`,{params:{connection:e.githubConnection}});if(!w(I))return;e.details=j.data,e.pullRequestId||(e.pullRequestId=_.repo+"-PR"+_.pullRequestId+"-"+generateRandomId(4))}catch(j){if(!w(I))return;throw j.data&&(i("ERRORS."+j.data.error).then(M=>{e.addToast({title:"Error",date:new Date,body:M}),e.error=M},console.error),te(j.data.error)),U("sourceUrl","missing",!1),j}finally{b(I)}}let le=He(new Map);function Ie(){let _=new Set,I=e.details&&e.details.pullRequest;if(!I)return _;typeof I.title=="string"&&_.add(I.title),typeof I.body=="string"&&_.add(I.body),typeof I.diff=="string"&&_.add(I.diff);let j=I.comments||[];for(let M of j)typeof M.author=="string"&&_.add(M.author),typeof M.body=="string"&&_.add(M.body);return _}let _e=Q("pr",()=>{let _=Ie(),I=Array.from(_);return I.length===0?null:{contents:I,options:ee()}},(_,I)=>{if(!Array.isArray(_?.contents)||_.contents.length!==I.contents.length||_.contents.some(v=>typeof v!="string"))throw Error("Invalid preview response");let j=I.contents,M=new Map;for(let v=0;v<j.length&&v<_.contents.length;v++)M.set(j[v],_.contents[v]);le.clear(),M.forEach((v,S)=>le.set(S,v))});e.anonymizePrContent=function(_){return _&&(le.has(_)?le.get(_):"")};async function Ae(){let _=parseGithubUrl(e.sourceUrl),I=h();try{if(z(),e.gistOAuthRequired=!1,e.githubConnections?.oauthConnected===!1){e.gistOAuthRequired=!0,U("sourceUrl","missing",!1);return}let j=await t.get(`/api/gist/source/${_.gistId}`);if(!w(I))return;e.details=j.data,e.gistId||(e.gistId="gist-"+_.gistId.substring(0,6)+"-"+generateRandomId(4))}catch(j){if(!w(I))return;if(j.data?.error==="github_oauth_required"){e.gistOAuthRequired=!0,U("sourceUrl","missing",!1);return}throw j.data&&(i("ERRORS."+j.data.error).then(M=>{e.addToast({title:"Error",date:new Date,body:M}),e.error=M},console.error),te(j.data.error)),U("sourceUrl","missing",!1),j}finally{b(I)}}let Ee=He(new Map);function Ve(){let _=new Set,I=e.details&&e.details.gist;if(!I)return _;typeof I.description=="string"&&_.add(I.description),typeof I.ownerLogin=="string"&&_.add(I.ownerLogin);let j=I.files||[];for(let v of j)typeof v.filename=="string"&&_.add(v.filename),typeof v.content=="string"&&_.add(v.content);let M=I.comments||[];for(let v of M)typeof v.author=="string"&&_.add(v.author),typeof v.body=="string"&&_.add(v.body);return _}let Se=Q("gist",()=>{let _=Ve(),I=Array.from(_);return I.length===0?null:{contents:I,options:ee()}},(_,I)=>{if(!Array.isArray(_?.contents)||_.contents.length!==I.contents.length||_.contents.some(v=>typeof v!="string"))throw Error("Invalid preview response");let j=I.contents,M=new Map;for(let v=0;v<j.length&&v<_.contents.length;v++)M.set(j[v],_.contents[v]);Ee.clear(),M.forEach((v,S)=>Ee.set(S,v)),Le()});e.anonymizeGistContent=function(_){return _&&(Ee.has(_)?Ee.get(_):"")},e.previewGistFiles=[];function Le(){let _=e.details&&e.details.gist&&e.details.gist.files||[];e.previewGistFiles=_.map(I=>({filename:e.anonymizeGistContent(I.filename),content:e.anonymizeGistContent(I.content),language:I.language}))}e.watch("details.gist.files",Le,!0),e.watch("terms",Le);function Ue(){let _=e.conference;if(e.conference_data=null,!_)return;let I=e.isUpdate&&_===e._originalConference;t.get("/api/conferences/"+_).then(j=>{e.conference===_&&(e.conference_data=j.data,e.conference_data.startDate=new Date(e.conference_data.startDate),e.conference_data.endDate=new Date(e.conference_data.endDate),!I&&(e.options.expirationDate=new Date(e.conference_data.endDate),e.options.expirationMode="remove",e.options.update=e.conference_data.options.update,e.options.image=e.conference_data.options.image
Line truncated
|
`):[],image:!!e.options.image,link:!!e.options.link,repoId:e.repoId};e.source&&e.source.branch&&(_.branchName=e.source.branch);try{let I=parseGithubUrl(e.sourceUrl);_.repoName=`${I.owner}/${I.repo}`}catch{}return _}function Q(_,I,j){let M=null,v=0,S=()=>{if(e.detectedType!==_)return;M&&a.cancel(M);let V=++v;e.previewStatus="loading",M=a(()=>{M=null;let F=I();if(!F){e.previewStatus="idle";return}t.post("/api/anonymize-preview",F).then(B=>{V===v&&(j(B.data,F),e.previewStatus="ready")}).catch(()=>{V===v&&(e.previewStatus="error")})},200)};return S.cancel=()=>{v++,M&&a.cancel(M),M=null},e.on("dispose",S.cancel),S}e.retryPreview=()=>{e.detectedType==="repo"&&oe(),e.detectedType==="pr"&&_e(),e.detectedType==="gist"&&Se()};let oe=Q("repo",()=>e.readme?{content:e.readme,options:ee()}:null,_=>{if(typeof _?.content!="string")throw Error("Invalid preview response");e.anonymize_readme=_.content;let I="";try{let M=parseGithubUrl(e.sourceUrl),v=e.source.branch||e.details&&e.details.defaultBranch||"main";I=`https://github.com/${M.owner}/${M.repo}/raw/${v}/`}catch{}let j=renderMD(e.anonymize_readme,I);e.html_readme=j,a(Prism.highlightAll,150)});function ue(){!e.anonymize||!e.anonymize.terms||(e.termsRegexWarning=!!e.terms&&!!e.terms.match(/[-[\]{}()*+?.,\\^$|#]/g),oe())}async function pe(){let _=parseGithubUrl(e.sourceUrl),I=h();try{z();let j=await t.get(`/api/pr/${_.owner}/${_.repo}/${_.pullRequestId}`,{params:{connection:e.githubConnection}});if(!w(I))return;e.details=j.data,e.pullRequestId||(e.pullRequestId=_.repo+"-PR"+_.pullRequestId+"-"+generateRandomId(4))}catch(j){if(!w(I))return;throw j.data&&(i("ERRORS."+j.data.error).then(M=>{e.addToast({title:"Error",date:new Date,body:M}),e.error=M},console.error),te(j.data.error)),U("sourceUrl","missing",!1),j}finally{b(I)}}let le=He(new Map);function Ie(){let _=new Set,I=e.details&&e.details.pullRequest;if(!I)return _;typeof I.title=="string"&&_.add(I.title),typeof I.body=="string"&&_.add(I.body),typeof I.diff=="string"&&_.add(I.diff);let j=I.comments||[];for(let M of j)typeof M.author=="string"&&_.add(M.author),typeof M.body=="string"&&_.add(M.body);return _}let _e=Q("pr",()=>{let _=Ie(),I=Array.from(_);return I.length===0?null:{contents:I,options:ee()}},(_,I)=>{if(!Array.isArray(_?.contents)||_.contents.length!==I.contents.length||_.contents.some(v=>typeof v!="string"))throw Error("Invalid preview response");let j=I.contents,M=new Map;for(let v=0;v<j.length&&v<_.contents.length;v++)M.set(j[v],_.contents[v]);le.clear(),M.forEach((v,S)=>le.set(S,v))});e.anonymizePrContent=function(_){return _&&(le.has(_)?le.get(_):"")};async function Ae(){let _=parseGithubUrl(e.sourceUrl),I=h();try{z(),e.gistOAuthRequired=!1,e.gistAppRequired=!1;let j=await t.get(`/api/gist/source/${_.gistId}`);if(!w(I))return;e.details=j.data,e.gistId||(e.gistId="gist-"+_.gistId.substring(0,6)+"-"+generateRandomId(4))}catch(j){if(!w(I))return;if(j.data?.error==="github_app_reconnect_required"){e.gistAppRequired=!0,U("sourceUrl","missing",!1);return}if(j.data?.error==="github_oauth_required"){e.gistOAuthRequired=!0,U("sourceUrl","missing",!1);return}throw j.data&&(i("ERRORS."+j.data.error).then(M=>{e.addToast({title:"Error",date:new Date,body:M}),e.error=M},console.error),te(j.data.error)),U("sourceUrl","missing",!1),j}finally{b(I)}}let Ee=He(new Map);function Ve(){let _=new Set,I=e.details&&e.details.gist;if(!I)return _;typeof I.description=="string"&&_.add(I.description),typeof I.ownerLogin=="string"&&_.add(I.ownerLogin);let j=I.files||[];for(let v of j)typeof v.filename=="string"&&_.add(v.filename),typeof v.content=="string"&&_.add(v.content);let M=I.comments||[];for(let v of M)typeof v.author=="string"&&_.add(v.author),typeof v.body=="string"&&_.add(v.body);return _}let Se=Q("gist",()=>{let _=Ve(),I=Array.from(_);return I.length===0?null:{contents:I,options:ee()}},(_,I)=>{if(!Array.isArray(_?.contents)||_.contents.length!==I.contents.length||_.contents.some(v=>typeof v!="string"))throw Error("Invalid preview response");let j=I.contents,M=new Map;for(let v=0;v<j.length&&v<_.contents.length;v++)M.set(j[v],_.contents[v]);Ee.clear(),M.forEach((v,S)=>Ee.set(S,v)),Le()});e.anonymizeGistContent=function(_){return _&&(Ee.has(_)?Ee.get(_):"")},e.previewGistFiles=[];function Le(){let _=e.details&&e.details.gist&&e.details.gist.files||[];e.previewGistFiles=_.map(I=>({filename:e.anonymizeGistContent(I.filename),content:e.anonymizeGistContent(I.content),language:I.language}))}e.watch("details.gist.files",Le,!0),e.watch("terms",Le);function Ue(){let _=e.conference;if(e.conference_data=null,!_)return;let I=e.isUpdate&&_===e._originalConference;t.get("/api/conferences/"+_).then(j=>{e.conference===_&&(e.conference_data=j.data,e.conference_data.startDate=new Date(e.conference_data.startDate),e.conference_data.endDate=new Date(e.conference_data.endDate),!I&&(e.options.expirationDate=new Date(e.conference_data.endDate),e.options.expirationMode="remove",e.options.update=e.conference_data.options.update,e.options.image=e.con
Line truncated
|
||||||
`).filter(S=>S),connection:e.githubConnection,fullName:`${j.owner}/${j.repo}`,repository:e.sourceUrl,reconnectRepositoryId:e.reconnectRepositoryId,options:e.options,source:e.source,conference:e.conference};e.details&&(M.options.pageSource=e.details.pageSource),z();let v=e.isUpdate?"/api/repo/"+e.repoId:"/api/repo/";t.post(v,M,{headers:{"Content-Type":"application/json"}}).then(()=>{R.clear(),window.location.href="/status/"+e.repoId},S=>{S.data&&(i("ERRORS."+S.data.error).then(V=>{e.error=V},console.error),te(S.data.error))}).finally(()=>{I.disabled=!1})},e.anonymizeGist=_=>{if(e.sourceLoading){e.error="Wait for the source to finish loading before saving.";return}if(ne())return;if(e.anonymize?.invalid||e.sourceUrlError){e.error="Please correct the highlighted fields before saving.";return}let I=_.currentTarget||_.target.closest?.("button")||_.target;I.disabled=!0;let j=parseGithubUrl(e.sourceUrl),M={gistId:e.gistId,terms:e.terms.trim().split(`
|
`).filter(S=>S),connection:e.githubConnection,fullName:`${j.owner}/${j.repo}`,repository:e.sourceUrl,reconnectRepositoryId:e.reconnectRepositoryId,options:e.options,source:e.source,conference:e.conference};e.details&&(M.options.pageSource=e.details.pageSource),z();let v=e.isUpdate?"/api/repo/"+e.repoId:"/api/repo/";t.post(v,M,{headers:{"Content-Type":"application/json"}}).then(()=>{R.clear(),window.location.href="/status/"+e.repoId},S=>{S.data&&(i("ERRORS."+S.data.error).then(V=>{e.error=V},console.error),te(S.data.error))}).finally(()=>{I.disabled=!1})},e.anonymizeGist=_=>{if(e.sourceLoading){e.error="Wait for the source to finish loading before saving.";return}if(ne())return;if(e.anonymize?.invalid||e.sourceUrlError){e.error="Please correct the highlighted fields before saving.";return}let I=_.currentTarget||_.target.closest?.("button")||_.target;I.disabled=!0;let j=parseGithubUrl(e.sourceUrl),M={gistId:e.gistId,terms:e.terms.trim().split(`
|
||||||
`).filter(S=>S),source:{gistId:j.gistId},options:e.options,conference:e.conference};z();let v=e.isUpdate?"/api/gist/"+e.gistId:"/api/gist/";t.post(v,M,{headers:{"Content-Type":"application/json"}}).then(()=>{R.clear(),window.location.href="/gist/"+e.gistId},S=>{S.data&&(i("ERRORS."+S.data.error).then(V=>{e.error=V},console.error),te(S.data.error))}).finally(()=>{I.disabled=!1})},e.anonymizePullRequest=_=>{if(e.sourceLoading){e.error="Wait for the source to finish loading before saving.";return}if(ne())return;if(e.anonymize?.invalid||e.sourceUrlError){e.error="Please correct the highlighted fields before saving.";return}let I=_.currentTarget||_.target.closest?.("button")||_.target;I.disabled=!0;let j=parseGithubUrl(e.sourceUrl),M={pullRequestId:e.pullRequestId,connection:e.githubConnection,terms:e.terms.trim().split(`
|
`).filter(S=>S),source:{gistId:j.gistId},options:e.options,conference:e.conference};z();let v=e.isUpdate?"/api/gist/"+e.gistId:"/api/gist/";t.post(v,M,{headers:{"Content-Type":"application/json"}}).then(()=>{R.clear(),window.location.href="/gist/"+e.gistId},S=>{S.data&&(i("ERRORS."+S.data.error).then(V=>{e.error=V},console.error),te(S.data.error))}).finally(()=>{I.disabled=!1})},e.anonymizePullRequest=_=>{if(e.sourceLoading){e.error="Wait for the source to finish loading before saving.";return}if(ne())return;if(e.anonymize?.invalid||e.sourceUrlError){e.error="Please correct the highlighted fields before saving.";return}let I=_.currentTarget||_.target.closest?.("button")||_.target;I.disabled=!0;let j=parseGithubUrl(e.sourceUrl),M={pullRequestId:e.pullRequestId,connection:e.githubConnection,terms:e.terms.trim().split(`
|
||||||
`).filter(S=>S),source:{repositoryFullName:`${j.owner}/${j.repo}`,pullRequestId:j.pullRequestId},options:e.options,conference:e.conference};z();let v=e.isUpdate?"/api/pr/"+e.pullRequestId:"/api/pr/";t.post(v,M,{headers:{"Content-Type":"application/json"}}).then(()=>{R.clear(),window.location.href="/pr/"+e.pullRequestId},S=>{S.data&&(i("ERRORS."+S.data.error).then(V=>{e.error=V},console.error),te(S.data.error))}).finally(()=>{I.disabled=!1})},e.watch("conference",()=>{Ue()}),e.watch("terms",()=>{e.detectedType==="repo"&&ue(),e.detectedType==="pr"&&_e(),e.detectedType==="gist"&&Se()}),e.watch("options.image",()=>{e.detectedType==="repo"&&ue(),e.detectedType==="pr"&&_e(),e.detectedType==="gist"&&Se()}),e.watch("options.link",()=>{e.detectedType==="repo"&&ue(),e.detectedType==="pr"&&_e(),e.detectedType==="gist"&&Se()}),e.watch("details",()=>{e.detectedType==="pr"&&_e(),e.detectedType==="gist"&&Se()},!0)},tr=function(e,t,n,r,s,i){let a=ct(),u=Kt();e.on("dark-mode",(O,G)=>{e.aceOption&&(G?e.aceOption.theme="nord_dark":e.aceOption.theme="chrome")});let f=0,m=!1;e.on("dispose",()=>{m=!0,f++,g&&g.resolve()}),e.files=[],e.isMac=/Mac|iPhone|iPad|iPod/.test(navigator.platform||navigator.userAgent),e.fileSearchQuery="",e.fileSearchResults=null,e.fileSearchLoading=!1,u(document,"keydown",function(O){if((O.metaKey||O.ctrlKey)&&O.key==="k"){O.preventDefault();var G=document.querySelector(".tree-search-input");G&&(G.focus(),G.select())}});var g=null;e.onFileSearchChange=function(){g&&(g.resolve(),g=null);let O=e.fileSearchQuery;if(!O||O.length<2){e.fileSearchResults=null,e.fileSearchLoading=!1;return}e.fileSearchLoading=!0;let G=i.defer();g=G,t.get(`/api/repo/${e.repoId}/files/search?q=${encodeURIComponent(O)}`,{timeout:G.promise}).then(function(J){if(!(m||g!==G)){g=null,e.fileSearchLoading=!1;var ee={};e.files.forEach(function(z){ee[(z.path||"")+"/"+z.name]=!0});for(var Q=[],oe={},ue=0;ue<J.data.length;ue++){var pe=J.data[ue];if(pe.path)for(var le=pe.path.split("/"),Ie="",_e=0;_e<le.length;_e++){var Ae=Ie;Ie=Ie?Ie+"/"+le[_e]:le[_e];var Ee=Ae+"/"+le[_e];!ee[Ee]&&!oe[Ee]&&(oe[Ee]=!0,Q.push({name:le[_e],path:Ae}))}}Q.sort(function(z,ne){return(z.path||"").split("/").length-(ne.path||"").split("/").length}),Q.length>0&&e.files.push.apply(e.files,Q);for(var Ve=[],Se=0;Se<J.data.length;Se++){var Le=J.data[Se],Ue=(Le.path||"")+"/"+Le.name;!ee[Ue]&&Le.size!=null&&(Ve.push(Le),ee[Ue]=!0)}Ve.length>0&&e.files.push.apply(e.files,Ve),e.fileSearchResults=J.data}},function(){!m&&g===G&&(g=null,e.fileSearchLoading=!1,e.fileSearchResults=[])})};let w={yml:"yaml",txt:"text",py:"python",js:"javascript",ts:"typescript"},h=["license","txt"],b=["png","jpg","jpeg","gif","svg","ico","bmp","tiff","tif","webp","avif","heif","heic"],E=["wav","mp3","ogg","wma","flac","aac","m4a"],k=["mp4","avi","webm","mov","mpg","mpeg","mkv","flv","wmv","3gp","3g2","m4v","f4v","f4p","f4a","f4b"];e.on("routeUpdate",function(O,G){if(e.repoId!=r.repoId)return C();if((r.path||"")!=e.filePath){e.filePath=r.path||"",e.paths=e.filePath.split("/").filter(J=>J&&J.trim().length>0),re();for(let J=0;J<e.paths.length-1;J++){let ee=J>0?e.paths.slice(0,J).join("/"):"";e.files.some(oe=>oe.path===ee)||e.getFiles(ee)}}});function R(){if(e.paths[0]!="")return;let O=["readme.md","readme.txt","readme.org","readme.1st","readme"],G={};for(let ee of e.files)ee.name.toLowerCase().indexOf("readme")>-1&&(G[ee.name.toLowerCase()]=ee.name);let J=null;for(let ee of O)if(G[ee]){J=ee;break}if(!J&&Object.keys(G).length>0&&(J=Object.keys(G)[0]),J){let ee=n.url();ee[ee.length-1]!="/"&&(ee+="/"),n.url(ee+encodePathForUrl(G[J]))}}e.fileCounts=null,e.getFiles=function(O){let G=e.repoId;return t.get(`/api/repo/${e.repoId}/files/?path=${encodeURIComponent(O)}&v=${e.options.lastUpdateDate}`).then(function(J){if(m||G!==e.repoId)return[];let ee=O||"";return e.files=e.files.filter(Q=>Q.path!==ee),e.files.push(...J.data),J.data},function(J){if(m||G!==e.repoId)return[];e.type="error",e.content=J&&J.data&&J.data.error||"unknown_error",e.files=[]})};function D(){let O=e.repoId;t.get(`/api/repo/${e.repoId}/files/counts`).then(function(G){m||O!==e.repoId||(e.fileCounts=G.data)},function(){e.fileCounts={}})}function T(){return e.files.filter(O=>O.name==e.paths[e.paths.length-1]&&O.path==e.paths.slice(0,e.paths.length-1).join("/"))[0]}var P=null;e.on("dispose",function(){P&&a.interval.cancel(P)});function H(O){if(m)return;let G=e.repoId;t.get(`/api/repo/${e.repoId}/options`).then(J=>{if(!(m||G!==e.repoId)){if(e.options=J.data,e.options.url){window.location=e.options.url;return}O&&O(J.data)}},J=>{if(!(m||G!==e.repoId)){var ee=J.data||{};if(ee.error==="rate_limited"&&ee.resetAt){let oe=function(){var ue=Math.max(0,Math.ceil((e.rateLimitResetAt-Date.now())/1e3));if(ue<=0)e.rateLimitCountdown="",e.rateLimitResetAt=0,P&&(a.interval.cancel(P),P=null),H(O);else{var pe=Math.floor(ue/60),le=ue%60;e.rateLimitCountdown=pe>0?pe+"m "+le+"s":le+"s"}};var Q=oe;e.type="rate_limited",e.rateLimitResetAt=ee.resetAt,P&&a.interval.canc
Line truncated
|
`).filter(S=>S),source:{repositoryFullName:`${j.owner}/${j.repo}`,pullRequestId:j.pullRequestId},options:e.options,conference:e.conference};z();let v=e.isUpdate?"/api/pr/"+e.pullRequestId:"/api/pr/";t.post(v,M,{headers:{"Content-Type":"application/json"}}).then(()=>{R.clear(),window.location.href="/pr/"+e.pullRequestId},S=>{S.data&&(i("ERRORS."+S.data.error).then(V=>{e.error=V},console.error),te(S.data.error))}).finally(()=>{I.disabled=!1})},e.watch("conference",()=>{Ue()}),e.watch("terms",()=>{e.detectedType==="repo"&&ue(),e.detectedType==="pr"&&_e(),e.detectedType==="gist"&&Se()}),e.watch("options.image",()=>{e.detectedType==="repo"&&ue(),e.detectedType==="pr"&&_e(),e.detectedType==="gist"&&Se()}),e.watch("options.link",()=>{e.detectedType==="repo"&&ue(),e.detectedType==="pr"&&_e(),e.detectedType==="gist"&&Se()}),e.watch("details",()=>{e.detectedType==="pr"&&_e(),e.detectedType==="gist"&&Se()},!0)},tr=function(e,t,n,r,s,i){let a=ct(),u=Kt();e.on("dark-mode",(O,G)=>{e.aceOption&&(G?e.aceOption.theme="nord_dark":e.aceOption.theme="chrome")});let f=0,m=!1;e.on("dispose",()=>{m=!0,f++,g&&g.resolve()}),e.files=[],e.isMac=/Mac|iPhone|iPad|iPod/.test(navigator.platform||navigator.userAgent),e.fileSearchQuery="",e.fileSearchResults=null,e.fileSearchLoading=!1,u(document,"keydown",function(O){if((O.metaKey||O.ctrlKey)&&O.key==="k"){O.preventDefault();var G=document.querySelector(".tree-search-input");G&&(G.focus(),G.select())}});var g=null;e.onFileSearchChange=function(){g&&(g.resolve(),g=null);let O=e.fileSearchQuery;if(!O||O.length<2){e.fileSearchResults=null,e.fileSearchLoading=!1;return}e.fileSearchLoading=!0;let G=i.defer();g=G,t.get(`/api/repo/${e.repoId}/files/search?q=${encodeURIComponent(O)}`,{timeout:G.promise}).then(function(J){if(!(m||g!==G)){g=null,e.fileSearchLoading=!1;var ee={};e.files.forEach(function(z){ee[(z.path||"")+"/"+z.name]=!0});for(var Q=[],oe={},ue=0;ue<J.data.length;ue++){var pe=J.data[ue];if(pe.path)for(var le=pe.path.split("/"),Ie="",_e=0;_e<le.length;_e++){var Ae=Ie;Ie=Ie?Ie+"/"+le[_e]:le[_e];var Ee=Ae+"/"+le[_e];!ee[Ee]&&!oe[Ee]&&(oe[Ee]=!0,Q.push({name:le[_e],path:Ae}))}}Q.sort(function(z,ne){return(z.path||"").split("/").length-(ne.path||"").split("/").length}),Q.length>0&&e.files.push.apply(e.files,Q);for(var Ve=[],Se=0;Se<J.data.length;Se++){var Le=J.data[Se],Ue=(Le.path||"")+"/"+Le.name;!ee[Ue]&&Le.size!=null&&(Ve.push(Le),ee[Ue]=!0)}Ve.length>0&&e.files.push.apply(e.files,Ve),e.fileSearchResults=J.data}},function(){!m&&g===G&&(g=null,e.fileSearchLoading=!1,e.fileSearchResults=[])})};let w={yml:"yaml",txt:"text",py:"python",js:"javascript",ts:"typescript"},h=["license","txt"],b=["png","jpg","jpeg","gif","svg","ico","bmp","tiff","tif","webp","avif","heif","heic"],E=["wav","mp3","ogg","wma","flac","aac","m4a"],k=["mp4","avi","webm","mov","mpg","mpeg","mkv","flv","wmv","3gp","3g2","m4v","f4v","f4p","f4a","f4b"];e.on("routeUpdate",function(O,G){if(e.repoId!=r.repoId)return C();if((r.path||"")!=e.filePath){e.filePath=r.path||"",e.paths=e.filePath.split("/").filter(J=>J&&J.trim().length>0),re();for(let J=0;J<e.paths.length-1;J++){let ee=J>0?e.paths.slice(0,J).join("/"):"";e.files.some(oe=>oe.path===ee)||e.getFiles(ee)}}});function R(){if(e.paths[0]!="")return;let O=["readme.md","readme.txt","readme.org","readme.1st","readme"],G={};for(let ee of e.files)ee.name.toLowerCase().indexOf("readme")>-1&&(G[ee.name.toLowerCase()]=ee.name);let J=null;for(let ee of O)if(G[ee]){J=ee;break}if(!J&&Object.keys(G).length>0&&(J=Object.keys(G)[0]),J){let ee=n.url();ee[ee.length-1]!="/"&&(ee+="/"),n.url(ee+encodePathForUrl(G[J]))}}e.fileCounts=null,e.getFiles=function(O){let G=e.repoId;return t.get(`/api/repo/${e.repoId}/files/?path=${encodeURIComponent(O)}&v=${e.options.lastUpdateDate}`).then(function(J){if(m||G!==e.repoId)return[];let ee=O||"";return e.files=e.files.filter(Q=>Q.path!==ee),e.files.push(...J.data),J.data},function(J){if(m||G!==e.repoId)return[];e.type="error",e.content=J&&J.data&&J.data.error||"unknown_error",e.files=[]})};function D(){let O=e.repoId;t.get(`/api/repo/${e.repoId}/files/counts`).then(function(G){m||O!==e.repoId||(e.fileCounts=G.data)},function(){e.fileCounts={}})}function T(){return e.files.filter(O=>O.name==e.paths[e.paths.length-1]&&O.path==e.paths.slice(0,e.paths.length-1).join("/"))[0]}var P=null;e.on("dispose",function(){P&&a.interval.cancel(P)});function H(O){if(m)return;let G=e.repoId;t.get(`/api/repo/${e.repoId}/options`).then(J=>{if(!(m||G!==e.repoId)){if(e.options=J.data,e.options.url){window.location=e.options.url;return}O&&O(J.data)}},J=>{if(!(m||G!==e.repoId)){var ee=J.data||{};if(ee.error==="rate_limited"&&ee.resetAt){let oe=function(){var ue=Math.max(0,Math.ceil((e.rateLimitResetAt-Date.now())/1e3));if(ue<=0)e.rateLimitCountdown="",e.rateLimitResetAt=0,P&&(a.interval.cancel(P),P=null),H(O);else{var pe=Math.floor(ue/60),le=ue%60;e.rateLimitCountdown=pe>0?pe+"m "+le+"s":le+"s"}};var Q=oe;e.type="rate_limited",e.rateLimitResetAt=ee.resetAt,P&&a.interval.canc
Line truncated
|
||||||
@@ -18,13 +18,13 @@ while being at
|
|||||||
`).map((ue,pe)=>pe===0?ue:oe+ue).join(`
|
`).map((ue,pe)=>pe===0?ue:oe+ue).join(`
|
||||||
`)}else typeof C=="number"||typeof C=="boolean"?Q=String(C):Q=JSON.stringify(C);ie.push(`${J}${Q}${ee}`)}),ie.push("}"),ie.join(`
|
`)}else typeof C=="number"||typeof C=="boolean"?Q=String(C):Q=JSON.stringify(C);ie.push(`${J}${Q}${ee}`)}),ie.push("}"),ie.join(`
|
||||||
`)}function m(D){let T=[],P="",H=/(\w+):(>=|<=|!=|>|<|=)?([^\s]+)/g,q=0,U;for(;U=H.exec(D);)P+=D.slice(q,U.index),q=H.lastIndex,T.push({key:U[1],op:U[2]||"=",val:U[3]});return P+=D.slice(q),{filters:T,free:P.trim().toLowerCase()}}function g(D,T){for(let P of T.filters){let H=(U,ie,re)=>{let C=parseFloat(U),O=parseFloat(ie);return re==="="?String(U)===String(ie):re==="!="?String(U)!==String(ie):re===">="?C>=O:re==="<="?C<=O:re===">"?C>O:re==="<"?C<O:!0},q;if(P.key==="code")q=D.displayMessage;else if(P.key==="module")q=D.module;else if(P.key==="status")q=D._status;else if(P.key==="url")q=D._url;else if(P.key==="repo")q=D._repoId;else if(P.key==="level")q=D.level;else continue;if(q==null||!H(q,P.val,P.op))return!1}return!(T.free&&((D.displayMessage||"")+" "+(D.module||"")+" "+(D._url||"")+" "+JSON.stringify(D.raw||[])).toLowerCase().indexOf(T.free)===-1)}function w(){let D=m(e.query.search||"");e.parsedFilterCount=D.filters.length;let T=e.query.bucket,P=e.entries.filter(q=>T&&q._bucket!==T?!1:g(q,D)),H=e.query.group;if(H){let q=re=>H==="module"?re.module:re.displayMessage||re.message||"_",U=new Map;for(let re of P){let C=q(re);if(U.has(C)){let O=U.get(C);O.count++,O._related.push(re),new Date(re.ts)>new Date(O.ts)&&(O.ts=re.ts,O._url=re._url,O._status=re._status),new Date(re.ts)<new Date(O._firstSeen)&&(O._firstSeen=re.ts)}else{let O=Object.assign({},re);O._key=`${H}:${C}`,O._related=[re],O._firstSeen=re.ts,O._lastHourCount=0,O.count=1,U.set(C,O)}}let ie=Date.now()-3600*1e3;for(let re of U.values())re._lastHourCount=re._related.filter(C=>new Date(C.ts).getTime()>=ie).length;P=Array.from(U.values())}else P=P.map((q,U)=>(q._key="row:"+U+":"+q.ts,q._related=[q],q._firstSeen=q.ts,q._lastHourCount=0,q.count=1,q));e.query.sort==="count"?P.sort((q,U)=>U.count-q.count||new Date(U.ts)-new Date(q.ts)):P.sort((q,U)=>new Date(U.ts)-new Date(q.ts)),e.visible=P}function h(D){let T=D?e.entries.length:0,P=D?e.pageSize:Math.max(e.pageSize,e.entries.length||e.pageSize);t.get("/api/admin/errors",{params:{offset:T,limit:P}}).then(H=>{let q=(H.data.entries||[]).map(u);e.entries=D?e.entries.concat(q):q,e.available=!!H.data.available,e.cap=H.data.max||e.cap,e.total=H.data.total||e.entries.length,w()},H=>console.error(H))}e.loadMore=()=>h(!0),e.canLoadMore=()=>e.entries.length<e.total;function b(){t.get("/api/admin/errors/stats").then(D=>{let T=D.data||{},P=T.prev24h?Math.round((T.last24h-T.prev24h)/T.prev24h*100):0;e.stats={last24h:T.last24h||0,prev24h:T.prev24h||0,delta:P,severity:T.severity||{error:0,warn:0,info:0},unique:T.unique||{error:0,warn:0,info:0},buckets:T.buckets||[],dropped:T.dropped||0}},D=>console.error(D))}function E(){h(),b()}e.barPx=(D,T)=>{let P=e.stats.buckets||[],H=0;for(let re of P)H=Math.max(H,(re.error||0)+(re.warn||0)+(re.info||0));if(!H)return 0;let q=(D.error||0)+(D.warn||0)+(D.info||0);if(!q)return 0;let U=Math.round(q/H*60),ie=D[T]||0;return Math.round(ie/q*U)},e.bucketTitle=D=>`${new Date(D.hour).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})} \xB7 ${D.error||0} err \xB7 ${D.warn||0} warn \xB7 ${D.info||0} info`,e.toggle=D=>{e.expanded[D._key]=!e.expanded[D._key]},e.setBucket=D=>{e.query.bucket=D},e.refreshNow=E,e.clearAll=()=>{confirm("Clear all captured errors?")&&t.delete("/api/admin/errors").then(E,D=>console.error(D))},e.exportCsv=()=>{let D=["ts","level","module","displayMessage","_status","_url","_repoId"],T=[D.join(",")];for(let U of e.visible)T.push(D.map(ie=>{let re=U[ie]==null?"":String(U[ie]);return/[",\n]/.test(re)?`"${re.replace(/"/g,'""')}"`:re}).join(","));let P=new Blob([T.join(`
|
`)}function m(D){let T=[],P="",H=/(\w+):(>=|<=|!=|>|<|=)?([^\s]+)/g,q=0,U;for(;U=H.exec(D);)P+=D.slice(q,U.index),q=H.lastIndex,T.push({key:U[1],op:U[2]||"=",val:U[3]});return P+=D.slice(q),{filters:T,free:P.trim().toLowerCase()}}function g(D,T){for(let P of T.filters){let H=(U,ie,re)=>{let C=parseFloat(U),O=parseFloat(ie);return re==="="?String(U)===String(ie):re==="!="?String(U)!==String(ie):re===">="?C>=O:re==="<="?C<=O:re===">"?C>O:re==="<"?C<O:!0},q;if(P.key==="code")q=D.displayMessage;else if(P.key==="module")q=D.module;else if(P.key==="status")q=D._status;else if(P.key==="url")q=D._url;else if(P.key==="repo")q=D._repoId;else if(P.key==="level")q=D.level;else continue;if(q==null||!H(q,P.val,P.op))return!1}return!(T.free&&((D.displayMessage||"")+" "+(D.module||"")+" "+(D._url||"")+" "+JSON.stringify(D.raw||[])).toLowerCase().indexOf(T.free)===-1)}function w(){let D=m(e.query.search||"");e.parsedFilterCount=D.filters.length;let T=e.query.bucket,P=e.entries.filter(q=>T&&q._bucket!==T?!1:g(q,D)),H=e.query.group;if(H){let q=re=>H==="module"?re.module:re.displayMessage||re.message||"_",U=new Map;for(let re of P){let C=q(re);if(U.has(C)){let O=U.get(C);O.count++,O._related.push(re),new Date(re.ts)>new Date(O.ts)&&(O.ts=re.ts,O._url=re._url,O._status=re._status),new Date(re.ts)<new Date(O._firstSeen)&&(O._firstSeen=re.ts)}else{let O=Object.assign({},re);O._key=`${H}:${C}`,O._related=[re],O._firstSeen=re.ts,O._lastHourCount=0,O.count=1,U.set(C,O)}}let ie=Date.now()-3600*1e3;for(let re of U.values())re._lastHourCount=re._related.filter(C=>new Date(C.ts).getTime()>=ie).length;P=Array.from(U.values())}else P=P.map((q,U)=>(q._key="row:"+U+":"+q.ts,q._related=[q],q._firstSeen=q.ts,q._lastHourCount=0,q.count=1,q));e.query.sort==="count"?P.sort((q,U)=>U.count-q.count||new Date(U.ts)-new Date(q.ts)):P.sort((q,U)=>new Date(U.ts)-new Date(q.ts)),e.visible=P}function h(D){let T=D?e.entries.length:0,P=D?e.pageSize:Math.max(e.pageSize,e.entries.length||e.pageSize);t.get("/api/admin/errors",{params:{offset:T,limit:P}}).then(H=>{let q=(H.data.entries||[]).map(u);e.entries=D?e.entries.concat(q):q,e.available=!!H.data.available,e.cap=H.data.max||e.cap,e.total=H.data.total||e.entries.length,w()},H=>console.error(H))}e.loadMore=()=>h(!0),e.canLoadMore=()=>e.entries.length<e.total;function b(){t.get("/api/admin/errors/stats").then(D=>{let T=D.data||{},P=T.prev24h?Math.round((T.last24h-T.prev24h)/T.prev24h*100):0;e.stats={last24h:T.last24h||0,prev24h:T.prev24h||0,delta:P,severity:T.severity||{error:0,warn:0,info:0},unique:T.unique||{error:0,warn:0,info:0},buckets:T.buckets||[],dropped:T.dropped||0}},D=>console.error(D))}function E(){h(),b()}e.barPx=(D,T)=>{let P=e.stats.buckets||[],H=0;for(let re of P)H=Math.max(H,(re.error||0)+(re.warn||0)+(re.info||0));if(!H)return 0;let q=(D.error||0)+(D.warn||0)+(D.info||0);if(!q)return 0;let U=Math.round(q/H*60),ie=D[T]||0;return Math.round(ie/q*U)},e.bucketTitle=D=>`${new Date(D.hour).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})} \xB7 ${D.error||0} err \xB7 ${D.warn||0} warn \xB7 ${D.info||0} info`,e.toggle=D=>{e.expanded[D._key]=!e.expanded[D._key]},e.setBucket=D=>{e.query.bucket=D},e.refreshNow=E,e.clearAll=()=>{confirm("Clear all captured errors?")&&t.delete("/api/admin/errors").then(E,D=>console.error(D))},e.exportCsv=()=>{let D=["ts","level","module","displayMessage","_status","_url","_repoId"],T=[D.join(",")];for(let U of e.visible)T.push(D.map(ie=>{let re=U[ie]==null?"":String(U[ie]);return/[",\n]/.test(re)?`"${re.replace(/"/g,'""')}"`:re}).join(","));let P=new Blob([T.join(`
|
||||||
`)],{type:"text/csv;charset=utf-8"}),H=URL.createObjectURL(P),q=document.createElement("a");q.href=H,q.download=`errors-${new Date().toISOString().slice(0,19)}.csv`,document.body.appendChild(q),q.click(),document.body.removeChild(q),URL.revokeObjectURL(H)};function k(D){e.copyHint=`${D} copied`,s.timeout(()=>{e.copyHint=""},1500)}e.copyJson=D=>{navigator.clipboard.writeText(D._detailJson).then(()=>k("JSON"))},e.copyCurl=D=>{if(!D._url)return;let P=`curl -X ${D._method||"GET"} '${window.location.origin}${D._url}'`;navigator.clipboard.writeText(P).then(()=>k("curl"))},E();let R=r(()=>{e.query.autoRefresh&&E()},15e3);e.on("dispose",()=>r.cancel(R)),e.watch("query.search",w),e.watch("query.bucket",w),e.watch("query.sort",w),e.watch("query.group",w)},el=function(e,t,n,r){if(e.Math=Math,e.watch("user.status",()=>{e.user==null&&n.url("/")}),e.user==null){n.url("/");return}e.data=null,e.loading=!0,e.error=null;function s(h){if(h==null)return"\u2014";for(var b=["B","KB","MB","GB","TB"],E=0,k=h;k>=1024&&E<b.length-1;)k/=1024,E++;return k.toFixed(E>0?1:0)+" "+b[E]}e.humanBytes=s;function i(h){if(!h)return"\u2014";var b=Math.floor(h/86400),E=Math.floor(h%86400/3600),k=Math.floor(h%3600/60);return b>0?b+"d "+(E<10?"0":"")+E+"h":E>0?E+"h "+(k<10?"0":"")+k+"m":k+"m"}e.humanDuration=i;function a(h){return h==null?"\u2014":h>=1e6?(h/1e6).toFixed(1)+"M":h>=1e3?(h/1e3).toFixed(1)+"K":String(h)}e.humanNum=a,e.queueTotal=function(h){return h?(h.waiting||0)+(h.active||0)+(h.delayed||0)+(h.failed||0):0},e.statusCount=function(h){if(!e.data||!e.data.repos)return 0;for(var b=e.data.repos.statusBreakdown||[],E=0;E<b.length;E++)if(b[E]._id===h)return b[E].count;return 0},e.barPct=function(h){var b=e.data&&e.data.repos?e.data.repos.total:0;if(!b)return 0;var E=[h];h==="expired"&&E.push("expiring"),h==="removed"&&E.push("removing"),h==="preparing"&&E.push("download");var k=0;return E.forEach(function(R){k+=e.statusCount(R)}),Math.max(.4,k/b*100)},e.errPct=function(h){if(!e.data||!e.data.errors)return 0;var b=Math.max(e.data.errors.severity.error,e.data.errors.severity.warn,e.data.errors.severity.info,1);return e.data.errors.severity[h]/b*100};function u(h){var b=h||[];return b.map(function(E,k){var R=b[k-1]||{},D=Object.assign({},E);return D.dailyRepositories=k?Math.max(0,(E.nbRepositories||0)-(R.nbRepositories||0)):0,D.dailyUsers=k?Math.max(0,(E.nbUsers||0)-(R.nbUsers||0)):0,D.dailyPageViews=k?Math.max(0,(E.nbPageViews||0)-(R.nbPageViews||0)):0,D})}function f(h){var b=h&&h.length?h[h.length-1]:{};return{repositories:b.dailyRepositories||0,users:b.dailyUsers||0,pageViews:b.dailyPageViews||0}}var m={};e.historyBarH=function(h,b){return!h||!m[b]?0:Math.max(1,Math.round(h[b]/m[b]*140))},e.historyLabel=function(h){if(!h||!h.date)return"";var b=new Date(h.date);return b.getUTCMonth()+1+"/"+b.getUTCDate()};function g(){t.get("/api/admin/overview").then(function(h){h.data.history=u(h.data.history),h.data.daily={today:f(h.data.history)},e.data=h.data,e.loading=!1,e.error=null,m={},(h.data.history||[]).forEach(function(b){["dailyPageViews","dailyRepositories","dailyUsers","nbUsers"].forEach(function(E){(!m[E]||b[E]>m[E])&&(m[E]=b[E])})})},function(h){e.loading=!1,e.error=h.data&&h.data.error||"Failed to load overview"})}g();var w=r(g,3e4);e.on("dispose",function(){r.cancel(w)})};var tl=[{path:"/connections",template:"partials/connections.htm",title:"GitHub connections \u2013 Anonymous GitHub",preserveExplorer:!1,setup:(e,t)=>Wa(e,t.http)},{path:"/signin",template:"partials/signin.htm",title:"Sign in \u2013 Anonymous GitHub",preserveExplorer:!1,setup:(e,t)=>Ka(e,t.http)},{path:"/",template:"partials/home.htm",title:"Anonymous GitHub \u2013 Share the code, not the author",preserveExplorer:!1,setup:(e,t)=>Ua(e,t.http,t.location,t.window,t.timeout)},{path:"/dashboard",template:"partials/dashboard.htm",title:"Your anonymizations \u2013 Anonymous GitHub",preserveExplorer:!1,setup:(e,t)=>Fa(e,t.http,t.location,t.promises,t.window,t.quotaService)},{path:"/pr-dashboard",redirect:"/dashboard"},{path:"/anonymize/:repoId?",template:"partials/anonymize.htm",title:"New anonymization \u2013 Anonymous GitHub",preserveExplorer:!1,setup:(e,t)=>en(e,t.http,t.html,t.params,t.location,t.translate,t.timeout)},{path:"/pull-request-anonymize/:pullRequestId?",template:"partials/anonymize.htm",title:"Anonymize a pull request \u2013 Anonymous GitHub",preserveExplorer:!1,setup:(e,t)=>en(e,t.http,t.html,t.params,t.location,t.translate,t.timeout)},{path:"/gist-anonymize/:gistId?",template:"partials/anonymize.htm",title:"Anonymize a gist \u2013 Anonymous GitHub",preserveExplorer:!1,setup:(e,t)=>en(e,t.http,t.html,t.params,t.location,t.translate,t.timeout)},{path:"/status/:repoId",template:"partials/status.htm",title:"Repository status \u2013 Anonymous GitHub",preserveExplorer:!1,setup:(e,t)=>za(e,t.http,t.params)},{path:"/conferences",template:"partials/conferences.htm",title:"Your conferences \u2013 Anonymous GitHub",preserveExplorer:!1,setup:(e,t)=>Ba(e,t.http,t.location)
Line truncated
|
`)],{type:"text/csv;charset=utf-8"}),H=URL.createObjectURL(P),q=document.createElement("a");q.href=H,q.download=`errors-${new Date().toISOString().slice(0,19)}.csv`,document.body.appendChild(q),q.click(),document.body.removeChild(q),URL.revokeObjectURL(H)};function k(D){e.copyHint=`${D} copied`,s.timeout(()=>{e.copyHint=""},1500)}e.copyJson=D=>{navigator.clipboard.writeText(D._detailJson).then(()=>k("JSON"))},e.copyCurl=D=>{if(!D._url)return;let P=`curl -X ${D._method||"GET"} '${window.location.origin}${D._url}'`;navigator.clipboard.writeText(P).then(()=>k("curl"))},E();let R=r(()=>{e.query.autoRefresh&&E()},15e3);e.on("dispose",()=>r.cancel(R)),e.watch("query.search",w),e.watch("query.bucket",w),e.watch("query.sort",w),e.watch("query.group",w)},el=function(e,t,n,r){if(e.Math=Math,e.watch("user.status",()=>{e.user==null&&n.url("/")}),e.user==null){n.url("/");return}e.data=null,e.loading=!0,e.error=null;function s(h){if(h==null)return"\u2014";for(var b=["B","KB","MB","GB","TB"],E=0,k=h;k>=1024&&E<b.length-1;)k/=1024,E++;return k.toFixed(E>0?1:0)+" "+b[E]}e.humanBytes=s;function i(h){if(!h)return"\u2014";var b=Math.floor(h/86400),E=Math.floor(h%86400/3600),k=Math.floor(h%3600/60);return b>0?b+"d "+(E<10?"0":"")+E+"h":E>0?E+"h "+(k<10?"0":"")+k+"m":k+"m"}e.humanDuration=i;function a(h){return h==null?"\u2014":h>=1e6?(h/1e6).toFixed(1)+"M":h>=1e3?(h/1e3).toFixed(1)+"K":String(h)}e.humanNum=a,e.queueTotal=function(h){return h?(h.waiting||0)+(h.active||0)+(h.delayed||0)+(h.failed||0):0},e.statusCount=function(h){if(!e.data||!e.data.repos)return 0;for(var b=e.data.repos.statusBreakdown||[],E=0;E<b.length;E++)if(b[E]._id===h)return b[E].count;return 0},e.barPct=function(h){var b=e.data&&e.data.repos?e.data.repos.total:0;if(!b)return 0;var E=[h];h==="expired"&&E.push("expiring"),h==="removed"&&E.push("removing"),h==="preparing"&&E.push("download");var k=0;return E.forEach(function(R){k+=e.statusCount(R)}),Math.max(.4,k/b*100)},e.errPct=function(h){if(!e.data||!e.data.errors)return 0;var b=Math.max(e.data.errors.severity.error,e.data.errors.severity.warn,e.data.errors.severity.info,1);return e.data.errors.severity[h]/b*100};function u(h){var b=h||[];return b.map(function(E,k){var R=b[k-1]||{},D=Object.assign({},E);return D.dailyRepositories=k?Math.max(0,(E.nbRepositories||0)-(R.nbRepositories||0)):0,D.dailyUsers=k?Math.max(0,(E.nbUsers||0)-(R.nbUsers||0)):0,D.dailyPageViews=k?Math.max(0,(E.nbPageViews||0)-(R.nbPageViews||0)):0,D})}function f(h){var b=h&&h.length?h[h.length-1]:{};return{repositories:b.dailyRepositories||0,users:b.dailyUsers||0,pageViews:b.dailyPageViews||0}}var m={};e.historyBarH=function(h,b){return!h||!m[b]?0:Math.max(1,Math.round(h[b]/m[b]*140))},e.historyLabel=function(h){if(!h||!h.date)return"";var b=new Date(h.date);return b.getUTCMonth()+1+"/"+b.getUTCDate()};function g(){t.get("/api/admin/overview").then(function(h){h.data.history=u(h.data.history),h.data.daily={today:f(h.data.history)},e.data=h.data,e.loading=!1,e.error=null,m={},(h.data.history||[]).forEach(function(b){["dailyPageViews","dailyRepositories","dailyUsers","nbUsers"].forEach(function(E){(!m[E]||b[E]>m[E])&&(m[E]=b[E])})})},function(h){e.loading=!1,e.error=h.data&&h.data.error||"Failed to load overview"})}g();var w=r(g,3e4);e.on("dispose",function(){r.cancel(w)})};var tl=[{path:"/connections",template:"partials/connections.htm",title:"GitHub connections \u2013 Anonymous GitHub",preserveExplorer:!1,setup:(e,t)=>Wa(e,t.http)},{path:"/signin",template:"partials/signin.htm",title:"Sign in \u2013 Anonymous GitHub",preserveExplorer:!1,setup:(e,t)=>Ka(e,t.http)},{path:"/",template:"partials/home.htm",title:"Anonymous GitHub \u2013 Share the code, not the author",preserveExplorer:!1,setup:(e,t)=>Ua(e,t.http,t.location,t.window,t.timeout)},{path:"/dashboard",template:"partials/dashboard.htm",title:"Your anonymizations \u2013 Anonymous GitHub",preserveExplorer:!1,setup:(e,t)=>Fa(e,t.http,t.location,t.promises,t.window,t.quotaService)},{path:"/pr-dashboard",redirect:"/dashboard"},{path:"/anonymize/:repoId?",template:"partials/anonymize.htm",title:"New anonymization \u2013 Anonymous GitHub",preserveExplorer:!1,setup:(e,t)=>en(e,t.http,t.html,t.params,t.location,t.translate,t.timeout)},{path:"/pull-request-anonymize/:pullRequestId?",template:"partials/anonymize.htm",title:"Anonymize a pull request \u2013 Anonymous GitHub",preserveExplorer:!1,setup:(e,t)=>en(e,t.http,t.html,t.params,t.location,t.translate,t.timeout)},{path:"/gist-anonymize/:gistId?",template:"partials/anonymize.htm",title:"Anonymize a gist \u2013 Anonymous GitHub",preserveExplorer:!1,setup:(e,t)=>en(e,t.http,t.html,t.params,t.location,t.translate,t.timeout)},{path:"/status/:repoId",template:"partials/status.htm",title:"Repository status \u2013 Anonymous GitHub",preserveExplorer:!1,setup:(e,t)=>za(e,t.http,t.params)},{path:"/conferences",template:"partials/conferences.htm",title:"Your conferences \u2013 Anonymous GitHub",preserveExplorer:!1,setup:(e,t)=>Ba(e,t.http,t.location)
Line truncated
|
||||||
anonymous_github`)])])])])]),p(" Limitations "),o("h4",{class:"faq-cat"},[o("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[o("use",{href:"#ui-icon-warning"})]),y("Limitations ")]),o("div",{class:"panel-group",id:"faq-limitations",role:"tablist","aria-multiselectable":"true"},[o("div",{class:"panel panel-default mb-3"},[o("div",{class:"panel-heading p-3",role:"tab",id:"headingLimitation"},[o("h3",{class:"panel-title"},[o("a",{class:"collapsed",role:"button","data-toggle":"collapse","data-parent":"#faq-limitations",href:"#limitation","aria-expanded":"false","aria-controls":"limitation"}," What are the limitations of Anonymous GitHub? ")])]),o("div",{id:"limitation",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingLimitation"},[o("div",{class:"panel-body p-3"},[o("ul",null,[o("li",null," Anonymous GitHub only anonymizes text-based files. Binary files (compiled executables, archives, etc.) are served as-is without anonymization. "),o("li",null," Files larger than 8 MB are not supported. "),o("li",null," Static site generators (such as Jekyll) used with GitHub Pages are not fully supported, although Markdown files are converted to HTML. "),o("li",null," The anonymization of terms within source code may change the behavior of the program (e.g., if a replaced term appears in a string literal or identifier). ")])])])])]),p(" Privacy & Security "),o("h4",{class:"faq-cat"},[o("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[o("use",{href:"#ui-icon-shield"})]),y("Privacy & Security ")]),o("div",{class:"panel-group",id:"faq-privacy",role:"tablist","aria-multiselectable":"true"},[o("div",{class:"panel panel-default mb-3"},[o("div",{class:"panel-heading p-3",role:"tab",id:"headingData"},[o("h3",{class:"panel-title"},[o("a",{class:"collapsed",role:"button","data-toggle":"collapse","data-parent":"#faq-privacy",href:"#data","aria-expanded":"false","aria-controls":"data"}," How is my data handled? ")])]),o("div",{id:"data",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingData"},[o("div",{class:"panel-body p-3"},[o("p",null," Data stored on Anonymous GitHub is never shared or used for any purpose beyond providing the anonymization service. When a repository is removed or expires, only its configuration is retained \u2014 this makes it easy to restore the repository if needed and ensures that no future repository reuses the same ID. ")])])]),o("div",{class:"panel panel-default mb-3"},[o("div",{class:"panel-heading p-3",role:"tab",id:"headingPermissions"},[o("h3",{class:"panel-title"},[o("a",{class:"collapsed",role:"button","data-toggle":"collapse","data-parent":"#faq-privacy",href:"#permissions","aria-expanded":"false","aria-controls":"permissions"}," Why does GitHub say Anonymous GitHub asks for write access? ")])]),o("div",{id:"permissions",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingPermissions"},[o("div",{class:"panel-body p-3"},[o("p",null,[y("The GitHub App has read-only access to the repositories you choose. You can change repository access on your "),o("a",{href:"/connections"},"GitHub connections"),y(" page.")]),o("p",null,"Legacy GitHub OAuth includes write access to private repositories because GitHub's OAuth scopes do not offer a read-only option for them. Existing OAuth anonymizations and gists can still use this connection."),o("p",null,"Anonymous GitHub reads repository content. It never pushes, modifies, or deletes files on GitHub.")])])]),o("div",{class:"panel panel-default mb-3"},[o("div",{class:"panel-heading p-3",role:"tab",id:"headingViewer"},[o("h3",{class:"panel-title"},[o("a",{class:"collapsed",role:"button","data-toggle":"collapse","data-parent":"#faq-privacy",href:"#viewer","aria-expanded":"false","aria-controls":"viewer"}," Can repository owners see who viewed their anonymized repository? ")])]),o("div",{id:"viewer",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingViewer"},[o("div",{class:"panel-body p-3"},[o("p",null," No. Only the total number of views is tracked as an incremental counter. It is not possible for the repository owner or for Anonymous GitHub to identify individual viewers. Reviewer anonymity is fully preserved. ")])])])]),p(" Self-Hosting "),o("h4",{class:"faq-cat"},[o("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[o("use",{href:"#project-icon-storage"})]),y("Self-Hosting ")]),o("div",{class:"panel-group",id:"faq-hosting",role:"tablist","aria-multiselectable":"true"},[o("div",{class:"panel panel-default mb-3"},[o("div",{class:"panel-heading p-3",role:"tab",id:"headingDeploy"},[o("h3",{class:"panel-title"},[o("a",{class:"collapsed",role:"button","data-toggle":"collapse","data-parent":"#faq-hosting",href:"#deploy","aria-expanded":"false","aria-controls":"deploy"}," Can I deploy my own instance? ")])]),o("div",{id:"deploy",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingDeploy"},[o("div",{class:"panel-body p-3"},[o("p",null,[y(" Yes. Anonymous Git
Line truncated
|
anonymous_github`)])])])])]),p(" Limitations "),o("h4",{class:"faq-cat"},[o("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[o("use",{href:"#ui-icon-warning"})]),y("Limitations ")]),o("div",{class:"panel-group",id:"faq-limitations",role:"tablist","aria-multiselectable":"true"},[o("div",{class:"panel panel-default mb-3"},[o("div",{class:"panel-heading p-3",role:"tab",id:"headingLimitation"},[o("h3",{class:"panel-title"},[o("a",{class:"collapsed",role:"button","data-toggle":"collapse","data-parent":"#faq-limitations",href:"#limitation","aria-expanded":"false","aria-controls":"limitation"}," What are the limitations of Anonymous GitHub? ")])]),o("div",{id:"limitation",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingLimitation"},[o("div",{class:"panel-body p-3"},[o("ul",null,[o("li",null," Anonymous GitHub only anonymizes text-based files. Binary files (compiled executables, archives, etc.) are served as-is without anonymization. "),o("li",null," Files larger than 8 MB are not supported. "),o("li",null," Static site generators (such as Jekyll) used with GitHub Pages are not fully supported, although Markdown files are converted to HTML. "),o("li",null," The anonymization of terms within source code may change the behavior of the program (e.g., if a replaced term appears in a string literal or identifier). ")])])])])]),p(" Privacy & Security "),o("h4",{class:"faq-cat"},[o("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[o("use",{href:"#ui-icon-shield"})]),y("Privacy & Security ")]),o("div",{class:"panel-group",id:"faq-privacy",role:"tablist","aria-multiselectable":"true"},[o("div",{class:"panel panel-default mb-3"},[o("div",{class:"panel-heading p-3",role:"tab",id:"headingData"},[o("h3",{class:"panel-title"},[o("a",{class:"collapsed",role:"button","data-toggle":"collapse","data-parent":"#faq-privacy",href:"#data","aria-expanded":"false","aria-controls":"data"}," How is my data handled? ")])]),o("div",{id:"data",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingData"},[o("div",{class:"panel-body p-3"},[o("p",null," Data stored on Anonymous GitHub is never shared or used for any purpose beyond providing the anonymization service. When a repository is removed or expires, only its configuration is retained \u2014 this makes it easy to restore the repository if needed and ensures that no future repository reuses the same ID. ")])])]),o("div",{class:"panel panel-default mb-3"},[o("div",{class:"panel-heading p-3",role:"tab",id:"headingPermissions"},[o("h3",{class:"panel-title"},[o("a",{class:"collapsed",role:"button","data-toggle":"collapse","data-parent":"#faq-privacy",href:"#permissions","aria-expanded":"false","aria-controls":"permissions"}," Why does GitHub say Anonymous GitHub asks for write access? ")])]),o("div",{id:"permissions",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingPermissions"},[o("div",{class:"panel-body p-3"},[o("p",null,[y("The GitHub App has read-only access to the repositories you choose. You can change repository access on your "),o("a",{href:"/connections"},"GitHub connections"),y(" page.")]),o("p",null,"Legacy GitHub OAuth includes write access to private repositories because GitHub's OAuth scopes do not offer a read-only option for them. Existing OAuth anonymizations and gists can still use this connection."),o("p",null,"Anonymous GitHub reads repository content. It never pushes, modifies, or deletes files on GitHub.")])])]),o("div",{class:"panel panel-default mb-3"},[o("div",{class:"panel-heading p-3",role:"tab",id:"headingViewer"},[o("h3",{class:"panel-title"},[o("a",{class:"collapsed",role:"button","data-toggle":"collapse","data-parent":"#faq-privacy",href:"#viewer","aria-expanded":"false","aria-controls":"viewer"}," Can repository owners see who viewed their anonymized repository? ")])]),o("div",{id:"viewer",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingViewer"},[o("div",{class:"panel-body p-3"},[o("p",null," No. Only the total number of views is tracked as an incremental counter. It is not possible for the repository owner or for Anonymous GitHub to identify individual viewers. Reviewer anonymity is fully preserved. ")])])])]),p(" Self-Hosting "),o("h4",{class:"faq-cat"},[o("svg",{class:"ui-icon mr-2","aria-hidden":"true"},[o("use",{href:"#project-icon-storage"})]),y("Self-Hosting ")]),o("div",{class:"panel-group",id:"faq-hosting",role:"tablist","aria-multiselectable":"true"},[o("div",{class:"panel panel-default mb-3"},[o("div",{class:"panel-heading p-3",role:"tab",id:"headingDeploy"},[o("h3",{class:"panel-title"},[o("a",{class:"collapsed",role:"button","data-toggle":"collapse","data-parent":"#faq-hosting",href:"#deploy","aria-expanded":"false","aria-controls":"deploy"}," Can I deploy my own instance? ")])]),o("div",{id:"deploy",class:"panel-collapse collapse",role:"tabpanel","aria-labelledby":"headingDeploy"},[o("div",{class:"panel-body p-3"},[o("p",null,[y(" Yes. Anonymous Git
Line truncated
|
||||||
anonymized repository often think it is about the paper, so the
|
anonymized repository often think it is about the paper, so the
|
||||||
label names the service and the tooltip says who to contact. `),t[12]||(t[12]=o("li",{class:"nav-item d-none d-lg-block"},[o("a",{class:"nav-link",target:"_blank",rel:"noopener",href:"https://github.com/tdurieux/anonymous_github/issues/new?template=issue_report.yml",title:"Report a problem with the Anonymous GitHub service. Questions about an anonymized repository or paper go to its authors.","data-offset":"30"},[o("svg",{class:"ui-icon d-lg-none mr-1","aria-hidden":"true"},[o("use",{href:"#ui-icon-bug"})]),y("Report a bug ")])],-1)),e.isDarkMode?p("v-if",!0):(l(),d("li",xI,[o("a",{class:"nav-link nav-icon",href:"#",title:"Switch to dark mode","aria-label":"Switch to dark mode",role:"button",onClick:t[0]||(t[0]=he(n=>{e.darkMode(!0)},["prevent"]))},[...t[7]||(t[7]=[o("svg",{class:"ui-icon","aria-hidden":"true"},[o("use",{href:"#ui-icon-moon"})],-1)])])])),e.isDarkMode?(l(),d("li",e4,[o("a",{class:"nav-link nav-icon",href:"#",title:"Switch to light mode","aria-label":"Switch to light mode",role:"button",onClick:t[1]||(t[1]=he(n=>{e.darkMode(!1)},["prevent"]))},[...t[8]||(t[8]=[o("svg",{class:"ui-icon","aria-hidden":"true"},[o("use",{href:"#ui-icon-sun"})],-1)])])])):p("v-if",!0),e.user?p("v-if",!0):(l(),d("li",t4,[...t[9]||(t[9]=[o("a",{class:"nav-link btn-signin",target:"_self",href:"/signin","data-offset":"30"},[o("i",{class:"fab fa-github mr-1"}),y(" Sign in ")],-1)])])),e.user?(l(),d("li",o4,[o("a",s4,[e.user?.photo?(l(),d("img",{key:0,width:"22",height:"22",class:"rounded-circle",src:e.safeUrl(e.user?.photo)},null,8,n4)):p("v-if",!0),o("span",r4,c(e.user?.username),1)]),o("div",i4,[o("h6",a4,"Signed in as @"+c(e.user?.username),1),t[10]||(t[10]=ce('<a class="dropdown-item" href="/profile"><svg class="ui-icon" aria-hidden="true"><use href="#project-icon-filter"></use></svg><span>Settings<small>Defaults, quotas, account</small></span></a><a class="dropdown-item" href="/connections"><i class="fab fa-github" aria-hidden="true"></i><span>GitHub connections<small>Repository access and OAuth</small></span></a><a class="dropdown-item" href="/claim"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-link"></use></svg><span>Claim an anonymization<small>Attach an existing mirror to your account</small></span></a><div class="dropdown-divider"></div><a class="dropdown-item" href="https://github.com/tdurieux/anonymous_github/issues/new?template=issue_report.yml" target="_blank" rel="noopener"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-bug"></use></svg><span>Report a bug<small>About this service, not a paper</small></span></a><a class="dropdown-item" href="https://github.com/tdurieux/anonymous_github/" target="_blank" rel="noopener"><i class="fab fa-github" aria-hidden="true"></i><span>Source code</span></a><a class="dropdown-item" href="https://ko-fi.com/tdurieux" target="_blank" rel="noopener"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-heart"></use></svg><span>Support the project</span></a><div class="dropdown-divider"></div><a class="dropdown-item" href="/api/user/logout" target="_self"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-logout"></use></svg><span>Sign out</span></a>',9))])])):p("v-if",!0)])])],2),e.generalMessage?(l(),d("div",{key:0,class:"navbar shadow generalMessage",innerHTML:e.sanitize(e.generalMessage)},null,8,l4)):p("v-if",!0)],64)}var d4={class:"paper-landing"},u4={class:"paper-hero"},c4={class:"paper-hero-copy"},p4={class:"paper-cta-row"},f4={key:0,href:"/signin",target:"_self",class:"btn-hero"},h4={key:1,href:"/anonymize",class:"btn-hero"},m4={class:"paper-stats paper-wrap",id:"metrics","aria-label":"Usage over the last 60 days"},v4={class:"paper-stats-grid"},g4={class:"paper-stat-value"},y4={class:"paper-stat-label"},b4=["viewBox"],w4=["x","y","width","height"],k4={key:1,class:"paper-stat-delta"},E4={class:"paper-features paper-wrap","aria-label":"Product features"},C4={class:"paper-features-list",role:"tablist","aria-label":"Features","aria-orientation":"vertical"},_4=["onClick","onKeydown","id","aria-controls","aria-selected","tabindex"],S4={class:"paper-eyebrow"},N4={class:"paper-feature-title"},D4={class:"paper-feature-more"},R4={class:"paper-feature-title paper-feature-title-m","aria-hidden":"true"},T4=["href","target"],A4={class:"paper-features-stage"},O4=["id","aria-labelledby"],I4={class:"paper-frame"},P4={class:"paper-frame-bar","aria-hidden":"true"},V4={class:"url"},q4=["src","alt"],M4={class:"paper-footer"},$4={class:"paper-footer-inner"},L4={class:"paper-footer-col"},U4={key:0,href:"/dashboard"},F4={key:1,href:"/conferences"},z4={class:"paper-footer-foot"};function El(e,t){return l(),d("div",d4,[p(" Hero: copy on the left, the product on the right "),o("section",u4,[o("div",c4,[t[2]||(t[2]=o("div",{class:"paper-eyebrow"},"For double-blind peer review",-1)),t[3]||(t[3]=o("h1",{class:"hero-title"},[y(" Share the code,"),o("br"),o("span",{class:"accent"},"not the author.")],-1)),t[4]||(t[4]=o("p",{class:"hero-subtitle
Line truncated
|
label names the service and the tooltip says who to contact. `),t[12]||(t[12]=o("li",{class:"nav-item d-none d-lg-block"},[o("a",{class:"nav-link",target:"_blank",rel:"noopener",href:"https://github.com/tdurieux/anonymous_github/issues/new?template=issue_report.yml",title:"Report a problem with the Anonymous GitHub service. Questions about an anonymized repository or paper go to its authors.","data-offset":"30"},[o("svg",{class:"ui-icon d-lg-none mr-1","aria-hidden":"true"},[o("use",{href:"#ui-icon-bug"})]),y("Report a bug ")])],-1)),e.isDarkMode?p("v-if",!0):(l(),d("li",e4,[o("a",{class:"nav-link nav-icon",href:"#",title:"Switch to dark mode","aria-label":"Switch to dark mode",role:"button",onClick:t[0]||(t[0]=he(n=>{e.darkMode(!0)},["prevent"]))},[...t[7]||(t[7]=[o("svg",{class:"ui-icon","aria-hidden":"true"},[o("use",{href:"#ui-icon-moon"})],-1)])])])),e.isDarkMode?(l(),d("li",t4,[o("a",{class:"nav-link nav-icon",href:"#",title:"Switch to light mode","aria-label":"Switch to light mode",role:"button",onClick:t[1]||(t[1]=he(n=>{e.darkMode(!1)},["prevent"]))},[...t[8]||(t[8]=[o("svg",{class:"ui-icon","aria-hidden":"true"},[o("use",{href:"#ui-icon-sun"})],-1)])])])):p("v-if",!0),e.user?p("v-if",!0):(l(),d("li",o4,[...t[9]||(t[9]=[o("a",{class:"nav-link btn-signin",target:"_self",href:"/signin","data-offset":"30"},[o("i",{class:"fab fa-github mr-1"}),y(" Sign in ")],-1)])])),e.user?(l(),d("li",s4,[o("a",n4,[e.user?.photo?(l(),d("img",{key:0,width:"22",height:"22",class:"rounded-circle",src:e.safeUrl(e.user?.photo)},null,8,r4)):p("v-if",!0),o("span",i4,c(e.user?.username),1)]),o("div",a4,[o("h6",l4,"Signed in as @"+c(e.user?.username),1),t[10]||(t[10]=ce('<a class="dropdown-item" href="/profile"><svg class="ui-icon" aria-hidden="true"><use href="#project-icon-filter"></use></svg><span>Settings<small>Defaults, quotas, account</small></span></a><a class="dropdown-item" href="/connections"><i class="fab fa-github" aria-hidden="true"></i><span>GitHub connections<small>Repository access and OAuth</small></span></a><a class="dropdown-item" href="/claim"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-link"></use></svg><span>Claim an anonymization<small>Attach an existing mirror to your account</small></span></a><div class="dropdown-divider"></div><a class="dropdown-item" href="https://github.com/tdurieux/anonymous_github/issues/new?template=issue_report.yml" target="_blank" rel="noopener"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-bug"></use></svg><span>Report a bug<small>About this service, not a paper</small></span></a><a class="dropdown-item" href="https://github.com/tdurieux/anonymous_github/" target="_blank" rel="noopener"><i class="fab fa-github" aria-hidden="true"></i><span>Source code</span></a><a class="dropdown-item" href="https://ko-fi.com/tdurieux" target="_blank" rel="noopener"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-heart"></use></svg><span>Support the project</span></a><div class="dropdown-divider"></div><a class="dropdown-item" href="/api/user/logout" target="_self"><svg class="ui-icon" aria-hidden="true"><use href="#ui-icon-logout"></use></svg><span>Sign out</span></a>',9))])])):p("v-if",!0)])])],2),e.generalMessage?(l(),d("div",{key:0,class:"navbar shadow generalMessage",innerHTML:e.sanitize(e.generalMessage)},null,8,d4)):p("v-if",!0)],64)}var u4={class:"paper-landing"},c4={class:"paper-hero"},p4={class:"paper-hero-copy"},f4={class:"paper-cta-row"},h4={key:0,href:"/signin",target:"_self",class:"btn-hero"},m4={key:1,href:"/anonymize",class:"btn-hero"},v4={class:"paper-stats paper-wrap",id:"metrics","aria-label":"Usage over the last 60 days"},g4={class:"paper-stats-grid"},y4={class:"paper-stat-value"},b4={class:"paper-stat-label"},w4=["viewBox"],k4=["x","y","width","height"],E4={key:1,class:"paper-stat-delta"},C4={class:"paper-features paper-wrap","aria-label":"Product features"},_4={class:"paper-features-list",role:"tablist","aria-label":"Features","aria-orientation":"vertical"},S4=["onClick","onKeydown","id","aria-controls","aria-selected","tabindex"],N4={class:"paper-eyebrow"},D4={class:"paper-feature-title"},R4={class:"paper-feature-more"},T4={class:"paper-feature-title paper-feature-title-m","aria-hidden":"true"},A4=["href","target"],O4={class:"paper-features-stage"},I4=["id","aria-labelledby"],P4={class:"paper-frame"},V4={class:"paper-frame-bar","aria-hidden":"true"},q4={class:"url"},M4=["src","alt"],$4={class:"paper-footer"},L4={class:"paper-footer-inner"},U4={class:"paper-footer-col"},F4={key:0,href:"/dashboard"},z4={key:1,href:"/conferences"},H4={class:"paper-footer-foot"};function El(e,t){return l(),d("div",u4,[p(" Hero: copy on the left, the product on the right "),o("section",c4,[o("div",p4,[t[2]||(t[2]=o("div",{class:"paper-eyebrow"},"For double-blind peer review",-1)),t[3]||(t[3]=o("h1",{class:"hero-title"},[y(" Share the code,"),o("br"),o("span",{class:"accent"},"not the author.")],-1)),t[4]||(t[4]=o("p",{class:"hero-subtitle
Line truncated
|
||||||
MIT CSAIL
|
MIT CSAIL
|
||||||
jane.smith@example.org`},OV={id:"termsHelp",class:"form-text text-muted"},IV={class:"invalid-feedback"},PV={id:"settings-display",class:"paper-settings-section"},VV={class:"form-group paper-check-list"},qV={class:"form-check"},MV={class:"form-check-input",type:"checkbox",id:"link",name:"link"},$V={class:"form-check"},LV={class:"form-check-input",type:"checkbox",id:"image",name:"image"},UV={class:"form-check"},FV={class:"form-check-input",type:"checkbox",id:"pdf",name:"pdf"},zV={class:"form-check"},HV={class:"form-check-input",type:"checkbox",id:"notebook",name:"notebook"},jV={id:"settings-features",class:"paper-settings-section"},BV={class:"form-group paper-check-list"},GV={class:"form-check"},WV={class:"form-check-input",type:"checkbox",id:"page",name:"page"},KV={class:"form-check"},YV={class:"form-check-input",type:"checkbox",id:"loc",name:"loc"},JV={class:"form-check"},QV={class:"form-check-input",type:"checkbox",id:"update",name:"update"},XV={class:"form-group"},ZV={class:"form-control",id:"mode",name:"mode"},xV={class:"form-text text-muted"},e5={id:"settings-expiration",class:"paper-settings-section"},t5={class:"form-group"},o5={class:"form-control",id:"expiration",name:"expiration"},s5={key:0,class:"draft-status",role:"status"},n5={key:1,class:"draft-status"},r5={class:"paper-settings-footer"},i5={key:0,class:"paper-inline-alert paper-inline-alert-error",role:"alert"},a5=["textContent"],l5={class:"paper-settings-actions"},d5=["disabled"],u5={key:0,class:"ui-icon mr-1","aria-hidden":"true"},c5={id:"settings-account",class:"paper-settings-section"},p5={class:"paper-account-card"},f5=["src"],h5={class:"paper-account-identity"},m5={class:"paper-account-name"},v5={class:"paper-danger-zone"},g5={key:0,class:"paper-inline-alert paper-inline-alert-error",role:"alert"},y5=["textContent"],b5=["disabled"];function Dl(e,t){let n=We("quota-usage"),r=ye("paper-scrollspy"),s=ye("field"),i=ye("form");return l(),d("div",kV,[t[52]||(t[52]=ce('<div class="paper-crumbs"><a href="/dashboard">My work</a> \xA0/\xA0 <span class="here">Settings</span></div><h1 class="paper-page-title">Your <em>settings</em></h1><p class="paper-page-lede">Defaults applied to every new anonymization, your quotas, and your account.</p>',3)),o("div",EV,[N((l(),d("aside",CV,[...t[4]||(t[4]=[ce('<div class="paper-settings-toc-head">On this page</div><nav><a href="#settings-quota">Quota</a><a href="#settings-terms">Terms to redact</a><a href="#settings-display">Display</a><a href="#settings-features">Features</a><a href="#settings-expiration">Expiration</a><a href="#settings-account">Account</a></nav>',2)])])),[[r]]),o("div",_V,[p(" Account usage shares the dashboard component. "),o("section",SV,[t[6]||(t[6]=o("div",{class:"paper-section-eyebrow"},"Quota",-1)),t[7]||(t[7]=o("p",{class:"paper-section-copy"},"What you are using across all your anonymizations. Conferences can lift these limits during a review window.",-1)),e.quota?(l(),qt(n,{key:0,quota:e.quota,fmt:e.fmt},null,8,["quota","fmt"])):p("v-if",!0),e.quota?p("v-if",!0):(l(),d("div",NV,[(l(),d(X,null,ae([1,2,3],(a,u)=>o("div",DV,[...t[5]||(t[5]=[o("div",{class:"quota-header"},[o("span",{class:"skeleton skeleton-line",style:{width:"40%"}}),o("span",{class:"skeleton skeleton-line",style:{width:"25%"}})],-1),o("div",{class:"quota-track"},null,-1)])])),64))]))]),N((l(),d("form",{class:"form needs-validation",name:"defaultsForm",novalidate:"",onSubmit:t[2]||(t[2]=he(a=>e.submitForm(a,()=>{e.saveDefault(a)}),["prevent"]))},[o("section",RV,[t[13]||(t[13]=o("div",{class:"paper-section-eyebrow"},"Terms to redact",-1)),t[14]||(t[14]=o("p",{class:"paper-section-copy"},"Pre-filled in every new anonymization. You can still edit the list per anonymization.",-1)),o("div",TV,[t[12]||(t[12]=o("label",{class:"paper-field-label",for:"terms"},"Default terms",-1)),N(o("textarea",AV,null,512),[[s,{state:e.viewState,set:a=>{e.terms=a},value:e.terms,form:"defaultsForm",options:{debounce:250}}]]),o("small",OV,[t[8]||(t[8]=y(" One term per line (regex allowed). Each match is replaced by ",-1)),o("code",null,c(e.site_options?.ANONYMIZATION_MASK||"XXX")+"-[N]",1),t[9]||(t[9]=y(", or use ",-1)),t[10]||(t[10]=o("code",null,"term=>replacement",-1)),t[11]||(t[11]=y(" to pick your own. ",-1))]),N(o("div",IV," Terms are in an invalid format ",512),[[Y,e.defaultsForm?.terms?.errors?.format]])])]),o("section",PV,[t[23]||(t[23]=o("div",{class:"paper-section-eyebrow"},"Display",-1)),t[24]||(t[24]=o("p",{class:"paper-section-copy"},"What reviewers can see inside an anonymized repository.",-1)),o("div",VV,[o("div",qV,[N(o("input",MV,null,512),[[s,{state:e.viewState,set:a=>{e.options.link=a},value:e.options?.link,form:"defaultsForm",options:{}}]]),t[15]||(t[15]=o("label",{class:"form-check-label",for:"link"},"Keep links",-1)),t[16]||(t[16]=o("small",{class:"form-text text-muted"},"Unchecked, every link in text files is removed.",-1))]),o("div",$V,[N(o("input",LV,null,512),[[s,{state:e.viewState,set:a=>{e.options.image=a},value:e.op
Line truncated
|
jane.smith@example.org`},IV={id:"termsHelp",class:"form-text text-muted"},PV={class:"invalid-feedback"},VV={id:"settings-display",class:"paper-settings-section"},qV={class:"form-group paper-check-list"},MV={class:"form-check"},$V={class:"form-check-input",type:"checkbox",id:"link",name:"link"},LV={class:"form-check"},UV={class:"form-check-input",type:"checkbox",id:"image",name:"image"},FV={class:"form-check"},zV={class:"form-check-input",type:"checkbox",id:"pdf",name:"pdf"},HV={class:"form-check"},jV={class:"form-check-input",type:"checkbox",id:"notebook",name:"notebook"},BV={id:"settings-features",class:"paper-settings-section"},GV={class:"form-group paper-check-list"},WV={class:"form-check"},KV={class:"form-check-input",type:"checkbox",id:"page",name:"page"},YV={class:"form-check"},JV={class:"form-check-input",type:"checkbox",id:"loc",name:"loc"},QV={class:"form-check"},XV={class:"form-check-input",type:"checkbox",id:"update",name:"update"},ZV={class:"form-group"},xV={class:"form-control",id:"mode",name:"mode"},e5={class:"form-text text-muted"},t5={id:"settings-expiration",class:"paper-settings-section"},o5={class:"form-group"},s5={class:"form-control",id:"expiration",name:"expiration"},n5={key:0,class:"draft-status",role:"status"},r5={key:1,class:"draft-status"},i5={class:"paper-settings-footer"},a5={key:0,class:"paper-inline-alert paper-inline-alert-error",role:"alert"},l5=["textContent"],d5={class:"paper-settings-actions"},u5=["disabled"],c5={key:0,class:"ui-icon mr-1","aria-hidden":"true"},p5={id:"settings-account",class:"paper-settings-section"},f5={class:"paper-account-card"},h5=["src"],m5={class:"paper-account-identity"},v5={class:"paper-account-name"},g5={class:"paper-danger-zone"},y5={key:0,class:"paper-inline-alert paper-inline-alert-error",role:"alert"},b5=["textContent"],w5=["disabled"];function Dl(e,t){let n=We("quota-usage"),r=ye("paper-scrollspy"),s=ye("field"),i=ye("form");return l(),d("div",EV,[t[52]||(t[52]=ce('<div class="paper-crumbs"><a href="/dashboard">My work</a> \xA0/\xA0 <span class="here">Settings</span></div><h1 class="paper-page-title">Your <em>settings</em></h1><p class="paper-page-lede">Defaults applied to every new anonymization, your quotas, and your account.</p>',3)),o("div",CV,[N((l(),d("aside",_V,[...t[4]||(t[4]=[ce('<div class="paper-settings-toc-head">On this page</div><nav><a href="#settings-quota">Quota</a><a href="#settings-terms">Terms to redact</a><a href="#settings-display">Display</a><a href="#settings-features">Features</a><a href="#settings-expiration">Expiration</a><a href="#settings-account">Account</a></nav>',2)])])),[[r]]),o("div",SV,[p(" Account usage shares the dashboard component. "),o("section",NV,[t[6]||(t[6]=o("div",{class:"paper-section-eyebrow"},"Quota",-1)),t[7]||(t[7]=o("p",{class:"paper-section-copy"},"What you are using across all your anonymizations. Conferences can lift these limits during a review window.",-1)),e.quota?(l(),qt(n,{key:0,quota:e.quota,fmt:e.fmt},null,8,["quota","fmt"])):p("v-if",!0),e.quota?p("v-if",!0):(l(),d("div",DV,[(l(),d(X,null,ae([1,2,3],(a,u)=>o("div",RV,[...t[5]||(t[5]=[o("div",{class:"quota-header"},[o("span",{class:"skeleton skeleton-line",style:{width:"40%"}}),o("span",{class:"skeleton skeleton-line",style:{width:"25%"}})],-1),o("div",{class:"quota-track"},null,-1)])])),64))]))]),N((l(),d("form",{class:"form needs-validation",name:"defaultsForm",novalidate:"",onSubmit:t[2]||(t[2]=he(a=>e.submitForm(a,()=>{e.saveDefault(a)}),["prevent"]))},[o("section",TV,[t[13]||(t[13]=o("div",{class:"paper-section-eyebrow"},"Terms to redact",-1)),t[14]||(t[14]=o("p",{class:"paper-section-copy"},"Pre-filled in every new anonymization. You can still edit the list per anonymization.",-1)),o("div",AV,[t[12]||(t[12]=o("label",{class:"paper-field-label",for:"terms"},"Default terms",-1)),N(o("textarea",OV,null,512),[[s,{state:e.viewState,set:a=>{e.terms=a},value:e.terms,form:"defaultsForm",options:{debounce:250}}]]),o("small",IV,[t[8]||(t[8]=y(" One term per line (regex allowed). Each match is replaced by ",-1)),o("code",null,c(e.site_options?.ANONYMIZATION_MASK||"XXX")+"-[N]",1),t[9]||(t[9]=y(", or use ",-1)),t[10]||(t[10]=o("code",null,"term=>replacement",-1)),t[11]||(t[11]=y(" to pick your own. ",-1))]),N(o("div",PV," Terms are in an invalid format ",512),[[Y,e.defaultsForm?.terms?.errors?.format]])])]),o("section",VV,[t[23]||(t[23]=o("div",{class:"paper-section-eyebrow"},"Display",-1)),t[24]||(t[24]=o("p",{class:"paper-section-copy"},"What reviewers can see inside an anonymized repository.",-1)),o("div",qV,[o("div",MV,[N(o("input",$V,null,512),[[s,{state:e.viewState,set:a=>{e.options.link=a},value:e.options?.link,form:"defaultsForm",options:{}}]]),t[15]||(t[15]=o("label",{class:"form-check-label",for:"link"},"Keep links",-1)),t[16]||(t[16]=o("small",{class:"form-text text-muted"},"Unchecked, every link in text files is removed.",-1))]),o("div",LV,[N(o("input",UV,null,512),[[s,{state:e.viewState,set:a=>{e.options.image=a},value:e.op
Line truncated
|
||||||
`);for(let w=0;w<g.length;w++){let h=g[w];if(h.startsWith("diff --git")){m(),f();continue}if(h.startsWith("--- ")){i&&i.lines.length&&m(),f().oldPath=h.replace(/^--- (a\/)?/,"").trim();continue}if(h.startsWith("+++ ")){f().newPath=h.replace(/^\+\+\+ (b\/)?/,"").trim();continue}if(!(h.startsWith("index ")||h.startsWith("similarity index")||h.startsWith("rename ")||h.startsWith("new file mode")||h.startsWith("deleted file mode")||h.startsWith("Binary files"))){if(h.startsWith("@@")){let b=h.match(/@@\s+-(\d+)(?:,\d+)?\s+\+(\d+)(?:,\d+)?\s+@@/);b&&(a=parseInt(b[1],10),u=parseInt(b[2],10)),f().lines.push({kind:"hunk",oldNo:"",newNo:"",text:h});continue}i&&(h.startsWith("+")?(i.lines.push({kind:"add",oldNo:"",newNo:u,text:h.slice(1)}),u++):h.startsWith("-")?(i.lines.push({kind:"remove",oldNo:a,newNo:"",text:h.slice(1)}),a++):(i.lines.push({kind:"ctx",oldNo:a,newNo:u,text:h.startsWith(" ")?h.slice(1):h}),a++,u++))}}return n(s,i),s.join("")}})({trustAsHtml:e=>e});function Vq(e,t){return e==null?"":Number(e).toLocaleString(void 0,t==null?{}:{minimumFractionDigits:t,maximumFractionDigits:t})}function qq(e){return String(e??"").toUpperCase()}function Mq(e,t,n=0){return(e||[]).slice(n,n+t)}function $q(e,t){return Array.isArray(e)?typeof t=="function"?e.filter(t):e:[]}function Lq(e,t){if(!t)return e||[];let n=Array.isArray(t)?t:[t];return[...e||[]].sort((r,s)=>{for(let i of n){let a=i[0]==="-"?-1:1;i=i.replace(/^[+-]/,"");let u=i.split(".").reduce((m,g)=>m?.[g],r),f=i.split(".").reduce((m,g)=>m?.[g],s);if(typeof u=="string"&&(u=u.toLowerCase()),typeof f=="string"&&(f=f.toLowerCase()),u!==f)return(u==null?-1:f==null?1:u<f?-1:1)*a}return 0})}function Uq(e,t){if(!e)return"";let n=new Date(e);if(isNaN(n))return String(e);if(!t||t==="mediumDate")return n.toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"});let r={yyyy:n.getFullYear(),MMM:n.toLocaleDateString(void 0,{month:"short"}),MM:String(n.getMonth()+1).padStart(2,"0"),dd:String(n.getDate()).padStart(2,"0"),d:n.getDate(),HH:String(n.getHours()).padStart(2,"0"),mm:String(n.getMinutes()).padStart(2,"0"),ss:String(n.getSeconds()).padStart(2,"0")};return t.replace(/yyyy|MMM|MM|dd|HH|mm|ss|d/g,s=>r[s])}function Fq(e,t){return(t?.[e]??t?.[e===1?"one":"other"]??"").replace(/\{\}/g,e??0)}var ql={ERRORS:{cache_busy:"Downloads are busy. Please try again shortly.",invalid_sort:"The selected sort order is invalid.",invalid_cursor:"This project page is no longer valid. Reload the list.",repository_changed:"The repository changed while processing. Please retry.",repository_job_cancelled:"The repository changed or was removed while processing.",storage_delete_failed:"Unable to remove cached files. Please try again later.",unknown_error:"Unknown error, contact the admin.",unreachable:"Anonymous GitHub is unreachable, contact the admin.",request_error:"Unable to download the file, check your connection or contact the admin.",not_found:"The requested resource could not be found.",not_connected:"You must be logged in to perform this action.",not_authorized:"You do not have permission to perform this action.",unable_to_connect_user:"Unable to connect your account. Please try again later.",user_not_found:"The requested user could not be found.",user_banned:"Your account has been banned. Contact the admin for more information.",repo_access_limited:"GitHub blocked access because the repository's organization restricts third-party OAuth apps. Ask an org owner to approve Anonymous GitHub under Settings \u2192 Third-party Access \u2192 OAuth app policy, or anonymize a personal fork instead.",repo_saml_enforcement:"The repository's organization enforces SAML single sign-on. Authorize your token for that organization (GitHub \u2192 Settings \u2192 Applications, or re-run the org's SSO sign-in), then retry. Alternatively, anonymize a personal fork.",repo_not_found:"The repository was not found on GitHub. Check the URL and spelling, make sure you are signed in to the account that can see it, and confirm the repo isn't hidden under an org that restricts third-party app access.",repo_empty:"The selected branch has no commits on GitHub. Push at least one commit, or pick a different branch, then retry.",repo_not_accessible:"Anonymous GitHub cannot access this repository. Verify the repository exists and that Anonymous GitHub has been authorized for the owning organization.",repository_archived:"This repository has been archived and its files are no longer available.",repository_expired:"The repository is expired.",invalid_status:"This action cannot be performed while the resource is in its current state.",repository_not_ready:"Anonymous GitHub is still processing the repository, it can take several minutes.",repository_not_accessible:"This repository is currently not accessible.",repo_is_updating:"Anonymous GitHub is still processing the repository, it can take several minutes.",invalid_repo:"The provided repository is not valid.",invalid_source_repository:"The repository source name
Line truncated
|
`);for(let w=0;w<g.length;w++){let h=g[w];if(h.startsWith("diff --git")){m(),f();continue}if(h.startsWith("--- ")){i&&i.lines.length&&m(),f().oldPath=h.replace(/^--- (a\/)?/,"").trim();continue}if(h.startsWith("+++ ")){f().newPath=h.replace(/^\+\+\+ (b\/)?/,"").trim();continue}if(!(h.startsWith("index ")||h.startsWith("similarity index")||h.startsWith("rename ")||h.startsWith("new file mode")||h.startsWith("deleted file mode")||h.startsWith("Binary files"))){if(h.startsWith("@@")){let b=h.match(/@@\s+-(\d+)(?:,\d+)?\s+\+(\d+)(?:,\d+)?\s+@@/);b&&(a=parseInt(b[1],10),u=parseInt(b[2],10)),f().lines.push({kind:"hunk",oldNo:"",newNo:"",text:h});continue}i&&(h.startsWith("+")?(i.lines.push({kind:"add",oldNo:"",newNo:u,text:h.slice(1)}),u++):h.startsWith("-")?(i.lines.push({kind:"remove",oldNo:a,newNo:"",text:h.slice(1)}),a++):(i.lines.push({kind:"ctx",oldNo:a,newNo:u,text:h.startsWith(" ")?h.slice(1):h}),a++,u++))}}return n(s,i),s.join("")}})({trustAsHtml:e=>e});function qq(e,t){return e==null?"":Number(e).toLocaleString(void 0,t==null?{}:{minimumFractionDigits:t,maximumFractionDigits:t})}function Mq(e){return String(e??"").toUpperCase()}function $q(e,t,n=0){return(e||[]).slice(n,n+t)}function Lq(e,t){return Array.isArray(e)?typeof t=="function"?e.filter(t):e:[]}function Uq(e,t){if(!t)return e||[];let n=Array.isArray(t)?t:[t];return[...e||[]].sort((r,s)=>{for(let i of n){let a=i[0]==="-"?-1:1;i=i.replace(/^[+-]/,"");let u=i.split(".").reduce((m,g)=>m?.[g],r),f=i.split(".").reduce((m,g)=>m?.[g],s);if(typeof u=="string"&&(u=u.toLowerCase()),typeof f=="string"&&(f=f.toLowerCase()),u!==f)return(u==null?-1:f==null?1:u<f?-1:1)*a}return 0})}function Fq(e,t){if(!e)return"";let n=new Date(e);if(isNaN(n))return String(e);if(!t||t==="mediumDate")return n.toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"});let r={yyyy:n.getFullYear(),MMM:n.toLocaleDateString(void 0,{month:"short"}),MM:String(n.getMonth()+1).padStart(2,"0"),dd:String(n.getDate()).padStart(2,"0"),d:n.getDate(),HH:String(n.getHours()).padStart(2,"0"),mm:String(n.getMinutes()).padStart(2,"0"),ss:String(n.getSeconds()).padStart(2,"0")};return t.replace(/yyyy|MMM|MM|dd|HH|mm|ss|d/g,s=>r[s])}function zq(e,t){return(t?.[e]??t?.[e===1?"one":"other"]??"").replace(/\{\}/g,e??0)}var ql={ERRORS:{cache_busy:"Downloads are busy. Please try again shortly.",invalid_sort:"The selected sort order is invalid.",invalid_cursor:"This project page is no longer valid. Reload the list.",repository_changed:"The repository changed while processing. Please retry.",repository_job_cancelled:"The repository changed or was removed while processing.",storage_delete_failed:"Unable to remove cached files. Please try again later.",unknown_error:"Unknown error, contact the admin.",unreachable:"Anonymous GitHub is unreachable, contact the admin.",request_error:"Unable to download the file, check your connection or contact the admin.",not_found:"The requested resource could not be found.",not_connected:"You must be logged in to perform this action.",not_authorized:"You do not have permission to perform this action.",unable_to_connect_user:"Unable to connect your account. Please try again later.",user_not_found:"The requested user could not be found.",user_banned:"Your account has been banned. Contact the admin for more information.",repo_access_limited:"GitHub blocked access because the repository's organization restricts third-party OAuth apps. Ask an org owner to approve Anonymous GitHub under Settings \u2192 Third-party Access \u2192 OAuth app policy, or anonymize a personal fork instead.",repo_saml_enforcement:"The repository's organization enforces SAML single sign-on. Authorize your token for that organization (GitHub \u2192 Settings \u2192 Applications, or re-run the org's SSO sign-in), then retry. Alternatively, anonymize a personal fork.",repo_not_found:"The repository was not found on GitHub. Check the URL and spelling, make sure you are signed in to the account that can see it, and confirm the repo isn't hidden under an org that restricts third-party app access.",repo_empty:"The selected branch has no commits on GitHub. Push at least one commit, or pick a different branch, then retry.",repo_not_accessible:"Anonymous GitHub cannot access this repository. Verify the repository exists and that Anonymous GitHub has been authorized for the owning organization.",repository_archived:"This repository has been archived and its files are no longer available.",repository_expired:"The repository is expired.",invalid_status:"This action cannot be performed while the resource is in its current state.",repository_not_ready:"Anonymous GitHub is still processing the repository, it can take several minutes.",repository_not_accessible:"This repository is currently not accessible.",repo_is_updating:"Anonymous GitHub is still processing the repository, it can take several minutes.",invalid_repo:"The provided repository is not valid.",invalid_source_repository:"The repository source name
Line truncated
|
||||||
/*! Bundled license information:
|
/*! Bundled license information:
|
||||||
|
|
||||||
@vue/shared/dist/shared.esm-bundler.js:
|
@vue/shared/dist/shared.esm-bundler.js:
|
||||||
|
|||||||
+30
-6
@@ -1,6 +1,7 @@
|
|||||||
|
import { registerGitHubToken } from "./github-token-context";
|
||||||
import { isConnected } from "../server/database";
|
import { isConnected } from "../server/database";
|
||||||
import { expireEmbeddedContent } from "./content-expiration";
|
import { expireEmbeddedContent } from "./content-expiration";
|
||||||
import { APP_PROVIDER, appError } from "./github-app";
|
import { APP_PROVIDER, appUserToken } from "./github-app";
|
||||||
import CredentialModel from "./model/credentials/credentials.model";
|
import CredentialModel from "./model/credentials/credentials.model";
|
||||||
import { getCredentialToken } from "./credentials";
|
import { getCredentialToken } from "./credentials";
|
||||||
import { RepositoryStatus } from "./types";
|
import { RepositoryStatus } from "./types";
|
||||||
@@ -50,16 +51,39 @@ export default class Gist {
|
|||||||
this.owner.model.isNew = false;
|
this.owner.model.isNew = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getToken() {
|
private async getAccess() {
|
||||||
if (config.GITHUB_APP_ENABLED && !(await getCredentialToken(this.owner.id)) && await CredentialModel.exists({ ownerId: this.owner.id, provider: APP_PROVIDER })) {
|
if (config.GITHUB_APP_ENABLED && await CredentialModel.exists({ ownerId: this.owner.id, provider: APP_PROVIDER })) {
|
||||||
throw appError("github_oauth_required");
|
const ownerId = this.owner.id;
|
||||||
|
const token = await appUserToken(ownerId);
|
||||||
|
registerGitHubToken(token, { quotaKey: `app-user:${ownerId}`, renew: () => appUserToken(ownerId) });
|
||||||
|
return { token, connection: "github-app" };
|
||||||
}
|
}
|
||||||
return (await getCredentialToken(this.owner.id, "github", { collection: "anonymizedgists", id: this._model._id })) || config.GITHUB_TOKEN;
|
return { token: (await getCredentialToken(this.owner.id, "github", { collection: "anonymizedgists", id: this._model._id })) || config.GITHUB_TOKEN,
|
||||||
|
connection: "oauth" };
|
||||||
|
}
|
||||||
|
|
||||||
|
async getToken() {
|
||||||
|
return (await this.getAccess()).token;
|
||||||
}
|
}
|
||||||
|
|
||||||
async download() {
|
async download() {
|
||||||
|
const access = await this.getAccess();
|
||||||
|
try {
|
||||||
|
await this.downloadContent(access.token);
|
||||||
|
} catch (error) {
|
||||||
|
// A stored credential can exist but have been revoked on GitHub.
|
||||||
|
// Ask the user to reconnect the provider that rejected the credential.
|
||||||
|
if ((error as { status?: number })?.status === 401) {
|
||||||
|
throw new AnonymousError(access.connection === "github-app" ? "github_app_reconnect_required" : "github_oauth_required",
|
||||||
|
{ httpStatus: 403, cause: error as Error });
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async downloadContent(token: string) {
|
||||||
logger.info("downloading gist", { gistId: this._model.source.gistId });
|
logger.info("downloading gist", { gistId: this._model.source.gistId });
|
||||||
const oct = octokit(await this.getToken());
|
const oct = octokit(token);
|
||||||
|
|
||||||
const gist_id = this._model.source.gistId;
|
const gist_id = this._model.source.gistId;
|
||||||
|
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ router.get("/connections", async (req, res) => {
|
|||||||
const prs = await PullRequestModel.find({ owner: user.id, status: { $ne: "removed" } }).select("pullRequestId source.repositoryFullName githubAccess status statusDate").lean();
|
const prs = await PullRequestModel.find({ owner: user.id, status: { $ne: "removed" } }).select("pullRequestId source.repositoryFullName githubAccess status statusDate").lean();
|
||||||
const gistCount = await GistModel.countDocuments({ owner: user.id, status: { $ne: "removed" } });
|
const gistCount = await GistModel.countDocuments({ owner: user.id, status: { $ne: "removed" } });
|
||||||
res.json({ csrf: req.session.githubConnectionCSRF, appEnabled: config.GITHUB_APP_ENABLED && config.GITHUB_APP_NEW_CONNECTIONS,
|
res.json({ csrf: req.session.githubConnectionCSRF, appEnabled: config.GITHUB_APP_ENABLED && config.GITHUB_APP_NEW_CONNECTIONS,
|
||||||
|
gistConnection: config.GITHUB_APP_ENABLED && credentials.some(c => c.provider === APP_PROVIDER) ? "github-app" : "oauth",
|
||||||
oauthEnabled: config.GITHUB_OAUTH_ENABLED, oauthConnected: !!(await getCredentialToken(user.id)), appConnected, appError: appErrorCode,
|
oauthEnabled: config.GITHUB_OAUTH_ENABLED, oauthConnected: !!(await getCredentialToken(user.id)), appConnected, appError: appErrorCode,
|
||||||
installations, gistCount, resources: [
|
installations, gistCount, resources: [
|
||||||
...repos.map(r => ({ type: "repository", id: r.repoId, name: r.source.repositoryName, connection: r.githubAccess?.kind || "oauth", status: r.status, statusDate: r.statusDate })),
|
...repos.map(r => ({ type: "repository", id: r.repoId, name: r.source.repositoryName, connection: r.githubAccess?.kind || "oauth", status: r.status, statusDate: r.statusDate })),
|
||||||
@@ -246,9 +247,10 @@ router.post("/connections/disconnect-oauth", async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
const user = await getUser(req);
|
const user = await getUser(req);
|
||||||
if (!(await CredentialModel.exists({ ownerId: user.id, provider: APP_PROVIDER, revoked: { $ne: true } }))) throw appError("another_login_required", 409);
|
if (!(await CredentialModel.exists({ ownerId: user.id, provider: APP_PROVIDER, revoked: { $ne: true } }))) throw appError("another_login_required", 409);
|
||||||
await appUserToken(user.id);
|
// Confirm the remaining login still works on GitHub before revoking OAuth.
|
||||||
|
await userInstallations(user.id);
|
||||||
const active = { owner: user.id, status: { $ne: "removed" }, "githubAccess.kind": { $ne: "github-app" } };
|
const active = { owner: user.id, status: { $ne: "removed" }, "githubAccess.kind": { $ne: "github-app" } };
|
||||||
if (await RepositoryModel.exists(active) || await PullRequestModel.exists(active) || await GistModel.exists({ owner: user.id, status: { $ne: "removed" } })) {
|
if (await RepositoryModel.exists(active) || await PullRequestModel.exists(active)) {
|
||||||
throw appError("oauth_resources_remaining", 409);
|
throw appError("oauth_resources_remaining", 409);
|
||||||
}
|
}
|
||||||
await revokeGrant(user.id, "github");
|
await revokeGrant(user.id, "github");
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
const { expect } = require("chai");
|
||||||
|
require("ts-node/register/transpile-only");
|
||||||
|
const github = require("../src/core/GitHubUtils");
|
||||||
|
const Gist = require("../src/core/Gist").default;
|
||||||
|
const Model = require("../src/core/model/anonymizedGists/anonymizedGists.model").default;
|
||||||
|
const { handleError } = require("../src/server/routes/route-utils");
|
||||||
|
|
||||||
|
describe("gist authentication errors", function () {
|
||||||
|
let original, gist, client;
|
||||||
|
beforeEach(function () {
|
||||||
|
original = github.octokit;
|
||||||
|
gist = new Gist(new Model({ source: { gistId: "example" }, gist: { files: [{ filename: "saved.txt", content: "saved" }] } }));
|
||||||
|
gist.getAccess = async () => ({ token: "rejected-token", connection: "oauth" });
|
||||||
|
client = { rest: { gists: { get: async () => ({ data: { files: {} } }) } }, paginate: async () => [], request: async () => ({ data: "raw" }) };
|
||||||
|
github.octokit = token => { expect(token).to.equal("rejected-token"); return client; };
|
||||||
|
});
|
||||||
|
afterEach(function () { github.octokit = original; });
|
||||||
|
for (const operation of ["metadata", "comments", "raw file"]) {
|
||||||
|
it("requests OAuth reconnection when GitHub rejects " + operation, async function () {
|
||||||
|
const failure = Object.assign(new Error("Bad credentials"), { status: 401 });
|
||||||
|
const reject = async () => { throw failure; };
|
||||||
|
if (operation === "metadata") client.rest.gists.get = reject;
|
||||||
|
if (operation === "comments") client.paginate = reject;
|
||||||
|
if (operation === "raw file") {
|
||||||
|
client.rest.gists.get = async () => ({ data: { files: { file: { filename: "large.txt", truncated: true, raw_url: "https://gist.githubusercontent.com/example/raw" } } } });
|
||||||
|
client.request = reject;
|
||||||
|
}
|
||||||
|
let error;
|
||||||
|
try { await gist.download(); } catch (caught) { error = caught; }
|
||||||
|
expect(error?.message).to.equal("github_oauth_required");
|
||||||
|
expect(error.cause).to.equal(failure);
|
||||||
|
let status, body;
|
||||||
|
handleError(error, { headersSent: false, status: value => { status = value; return { json: value => { body = value; } }; } });
|
||||||
|
expect(status).to.equal(403);
|
||||||
|
expect(body).to.deep.equal({ error: "github_oauth_required" });
|
||||||
|
expect(gist.model.gist.files[0].content).to.equal("saved");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (const status of [403, 404, 429, 500]) {
|
||||||
|
it("preserves non-authentication GitHub errors: " + status, async function () {
|
||||||
|
const failure = Object.assign(new Error("Other GitHub failure"), { status });
|
||||||
|
client.rest.gists.get = async () => { throw failure; };
|
||||||
|
let error;
|
||||||
|
try { await gist.download(); } catch (caught) { error = caught; }
|
||||||
|
expect(error).to.equal(failure);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
it("requests App reconnection when an App user token is rejected", async function () {
|
||||||
|
gist.getAccess = async () => ({ token: "rejected-token", connection: "github-app" });
|
||||||
|
client.rest.gists.get = async () => { throw Object.assign(new Error("Bad credentials"), { status: 401 }); };
|
||||||
|
let error;
|
||||||
|
try { await gist.download(); } catch (caught) { error = caught; }
|
||||||
|
expect(error?.message).to.equal("github_app_reconnect_required");
|
||||||
|
});
|
||||||
|
it("still downloads a gist when the credential is accepted", async function () {
|
||||||
|
await gist.download();
|
||||||
|
expect(gist.model.gist.files).to.have.length(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
+105
-1
@@ -175,7 +175,7 @@ describeMongo("GitHub App credential and repository integration", function () {
|
|||||||
const result = String(url).endsWith("/token/scoped")
|
const result = String(url).endsWith("/token/scoped")
|
||||||
? scopeHandler ? await scopeHandler(body, options) : { status: 403 }
|
? scopeHandler ? await scopeHandler(body, options) : { status: 403 }
|
||||||
: await handler(String(url), options, body);
|
: await handler(String(url), options, body);
|
||||||
return new globalThis.Response(JSON.stringify(result.body || result), { status: result.status || 200, headers: { "content-type": "application/json" } });
|
return new globalThis.Response(JSON.stringify(result.body || result), { status: result.status || 200, headers: { "content-type": "application/json", ...result.headers } });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
it("keeps OAuth and App grants separate, encrypted and migration-verifiable", async () => {
|
it("keeps OAuth and App grants separate, encrypted and migration-verifiable", async () => {
|
||||||
@@ -191,6 +191,68 @@ describeMongo("GitHub App credential and repository integration", function () {
|
|||||||
expect(projected.encryptedToken).to.equal(undefined);
|
expect(projected.encryptedToken).to.equal(undefined);
|
||||||
expect(await verifyCredentials(mongoose.connection.db, createTokenCipher(keys, "test"))).to.deep.equal({ checked: 2, legacy: 0 });
|
expect(await verifyCredentials(mongoose.connection.db, createTokenCipher(keys, "test"))).to.deep.equal({ checked: 2, legacy: 0 });
|
||||||
});
|
});
|
||||||
|
for (const legacy of [false, true]) {
|
||||||
|
it(`reads gist files and comments with an App user grant (legacy: ${legacy})`, async () => {
|
||||||
|
if (legacy) await setCredential(owner.id, "legacy-secret");
|
||||||
|
await app.saveAppGrant(owner.id, data("old", -1));
|
||||||
|
mock((url, options, body) => {
|
||||||
|
if (url.includes("/login/oauth/access_token")) {
|
||||||
|
expect(body.refresh_token).to.equal("ghr_refreshold");
|
||||||
|
return data("new");
|
||||||
|
}
|
||||||
|
expect(new globalThis.Headers(options.headers).get("authorization")).to.equal("token ghu_accessnew");
|
||||||
|
if (url.includes("/comments")) return [{ body: "comment", user: { login: "owner" } }];
|
||||||
|
expect(url).to.include("/gists/example");
|
||||||
|
return { description: "gist", files: { file: { filename: "file.txt", content: "hello" } } };
|
||||||
|
});
|
||||||
|
const Gist = require("../src/core/Gist").default;
|
||||||
|
const Model = require("../src/core/model/anonymizedGists/anonymizedGists.model").default;
|
||||||
|
const gist = new Gist(new Model({ owner: owner.id, source: { gistId: "example" } }));
|
||||||
|
await gist.download();
|
||||||
|
expect(gist.model.gist.files[0].content).to.equal("hello");
|
||||||
|
expect(gist.model.gist.comments[0].body).to.equal("comment");
|
||||||
|
expect(calls).to.have.length(3);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (const rejected of [false, true]) {
|
||||||
|
it(`renews App gist access during comment pagination (401: ${rejected})`, async () => {
|
||||||
|
await app.saveAppGrant(owner.id, data("old"));
|
||||||
|
let pages = 0, refreshed = false;
|
||||||
|
mock(async (url, options) => {
|
||||||
|
if (url.includes("/login/oauth/access_token")) { refreshed = true; return data("new"); }
|
||||||
|
const authorization = new globalThis.Headers(options.headers).get("authorization");
|
||||||
|
if (url.includes("/comments")) {
|
||||||
|
pages++;
|
||||||
|
if (pages === 1) {
|
||||||
|
expect(authorization).to.equal("token ghu_accessold");
|
||||||
|
await Credentials.updateOne({ ownerId: owner.id, provider: app.APP_PROVIDER }, { $set: { expiresAt: new Date(0) } });
|
||||||
|
if (rejected) return { status: 401, body: { message: "Bad credentials" } };
|
||||||
|
return { body: [{ body: "first", user: { login: "owner" } }], headers: { link: '<https://api.github.com/gists/example/comments?page=2>; rel="next"' } };
|
||||||
|
}
|
||||||
|
expect(authorization).to.equal("token ghu_accessnew");
|
||||||
|
return [{ body: "last", user: { login: "owner" } }];
|
||||||
|
}
|
||||||
|
return { files: {} };
|
||||||
|
});
|
||||||
|
const Gist = require("../src/core/Gist").default;
|
||||||
|
const Model = require("../src/core/model/anonymizedGists/anonymizedGists.model").default;
|
||||||
|
const gist = new Gist(new Model({ owner: owner.id, source: { gistId: "example" } }));
|
||||||
|
await gist.download();
|
||||||
|
expect(refreshed).to.equal(true);
|
||||||
|
expect(pages).to.equal(2);
|
||||||
|
expect(gist.model.gist.comments.map(c => c.body)).to.deep.equal(rejected ? ["last"] : ["first", "last"]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
it("keeps legacy gist access but does not bypass revoked App grants", async () => {
|
||||||
|
await setCredential(owner.id, "legacy-secret");
|
||||||
|
const Gist = require("../src/core/Gist").default;
|
||||||
|
const Model = require("../src/core/model/anonymizedGists/anonymizedGists.model").default;
|
||||||
|
const gist = new Gist(new Model({ owner: owner.id, source: { gistId: "example" } }));
|
||||||
|
expect(await gist.getToken()).to.equal("legacy-secret");
|
||||||
|
await app.saveAppGrant(owner.id, data());
|
||||||
|
await Credentials.updateOne({ ownerId: owner.id, provider: app.APP_PROVIDER }, { $set: { revoked: true } });
|
||||||
|
await rejects(gist.download(), "github_app_reconnect_required");
|
||||||
|
});
|
||||||
it("serializes refresh and atomically rotates the token pair", async () => {
|
it("serializes refresh and atomically rotates the token pair", async () => {
|
||||||
await app.saveAppGrant(owner.id, data("old", -1));
|
await app.saveAppGrant(owner.id, data("old", -1));
|
||||||
mock(async (_url, _options, body) => {
|
mock(async (_url, _options, body) => {
|
||||||
@@ -415,6 +477,48 @@ describeMongo("GitHub App credential and repository integration", function () {
|
|||||||
headers: { "Content-Type": "application/json", "X-CSRF-Token": csrf }, body: body ? JSON.stringify(body) : undefined });
|
headers: { "Content-Type": "application/json", "X-CSRF-Token": csrf }, body: body ? JSON.stringify(body) : undefined });
|
||||||
return { status: response.status, location: response.headers.get("location"), data: await response.json().catch(() => null) };
|
return { status: response.status, location: response.headers.get("location"), data: await response.json().catch(() => null) };
|
||||||
}
|
}
|
||||||
|
it("allows OAuth revocation with an existing gist and keeps gist access working", async () => {
|
||||||
|
await setCredential(owner.id, "legacy-secret");
|
||||||
|
await app.saveAppGrant(owner.id, data());
|
||||||
|
const Model = require("../src/core/model/anonymizedGists/anonymizedGists.model").default;
|
||||||
|
const model = await Model.create({ owner: owner.id, gistId: "oauth-revoke-gist", source: { gistId: "example" } });
|
||||||
|
mock((url, options, body) => {
|
||||||
|
if (url.includes("/user/installations")) {
|
||||||
|
expect(new globalThis.Headers(options.headers).get("authorization")).to.equal("Bearer ghu_access1");
|
||||||
|
return { installations: [] };
|
||||||
|
}
|
||||||
|
if (url.includes("/grant")) {
|
||||||
|
expect(options.method).to.equal("DELETE");
|
||||||
|
expect(body.access_token).to.equal("legacy-secret");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
expect(new globalThis.Headers(options.headers).get("authorization")).to.equal("token ghu_access1");
|
||||||
|
return url.includes("/comments") ? [] : { files: { file: { filename: "file.txt", content: "still accessible" } } };
|
||||||
|
});
|
||||||
|
const result = await request("/github/connections/disconnect-oauth", {});
|
||||||
|
expect(result.status).to.equal(200);
|
||||||
|
expect(await getCredentialToken(owner.id)).not.to.be.ok;
|
||||||
|
const Gist = require("../src/core/Gist").default;
|
||||||
|
const gist = new Gist(model);
|
||||||
|
await gist.download();
|
||||||
|
expect(gist.model.gist.files[0].content).to.equal("still accessible");
|
||||||
|
});
|
||||||
|
for (const status of [401, 503]) {
|
||||||
|
it(`preserves OAuth when GitHub cannot verify the App grant (${status})`, async () => {
|
||||||
|
await setCredential(owner.id, "legacy-secret");
|
||||||
|
await app.saveAppGrant(owner.id, data());
|
||||||
|
mock((url, options) => {
|
||||||
|
expect(url).to.include("/user/installations");
|
||||||
|
expect(options.method).not.to.equal("DELETE");
|
||||||
|
return { status, body: { message: "unavailable" } };
|
||||||
|
});
|
||||||
|
const result = await request("/github/connections/disconnect-oauth", {});
|
||||||
|
expect(result.status).to.equal(status === 401 ? 403 : 502);
|
||||||
|
expect(result.data.error).to.equal(status === 401 ? "github_app_reconnect_required" : "github_unavailable");
|
||||||
|
expect(await getCredentialToken(owner.id)).to.equal("legacy-secret");
|
||||||
|
expect(calls).to.have.length(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
it("links App authorization to the existing OAuth account without replacing its grant", async () => {
|
it("links App authorization to the existing OAuth account without replacing its grant", async () => {
|
||||||
await setCredential(owner.id, "legacy-secret");
|
await setCredential(owner.id, "legacy-secret");
|
||||||
owner.isAdmin = true; await owner.save();
|
owner.isAdmin = true; await owner.save();
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ describe("production regressions", function () {
|
|||||||
it("fetches complete truncated gist content", async function () {
|
it("fetches complete truncated gist content", async function () {
|
||||||
const Gist = require("../src/core/Gist").default;
|
const Gist = require("../src/core/Gist").default;
|
||||||
const model = new (require("../src/core/model/anonymizedGists/anonymizedGists.model").default)({ source: { gistId: "123" } });
|
const model = new (require("../src/core/model/anonymizedGists/anonymizedGists.model").default)({ source: { gistId: "123" } });
|
||||||
const gist = new Gist(model); gist.getToken = async () => "private-token";
|
const gist = new Gist(model); gist.getAccess = async () => ({ token: "private-token", connection: "github-app" });
|
||||||
stub(gh, "octokit", token => {
|
stub(gh, "octokit", token => {
|
||||||
expect(token).to.equal("private-token");
|
expect(token).to.equal("private-token");
|
||||||
return { rest: { gists: { get: async () => ({ data: { files: { file: { filename: "file", content: "prefix", truncated: true, raw_url: "https://gist.githubusercontent.com/raw", size: 20 } } } }) } },
|
return { rest: { gists: { get: async () => ({ data: { files: { file: { filename: "file", content: "prefix", truncated: true, raw_url: "https://gist.githubusercontent.com/raw", size: 20 } } } }) } },
|
||||||
|
|||||||
+29
-4
@@ -469,17 +469,23 @@ describe("Vue 3 UI", function () {
|
|||||||
expect(ui.window.document.querySelector('a[href="/github/app/login"]')).to.equal(null);
|
expect(ui.window.document.querySelector('a[href="/github/app/login"]')).to.equal(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("offers OAuth for an App-only gist and saves the draft before connecting", async function () {
|
for (const provider of ["OAuth", "App"]) {
|
||||||
|
it(`offers ${provider} recovery when gist credentials are rejected`, async function () {
|
||||||
ui = await browser("/gist-anonymize", {
|
ui = await browser("/gist-anonymize", {
|
||||||
"/api/user": { username: "owner" },
|
"/api/user": { username: "owner" },
|
||||||
"/github/connections": { appEnabled: true, appConnected: true, oauthEnabled: true, oauthConnected: false },
|
"/github/connections": { appEnabled: true, appConnected: provider === "App", oauthEnabled: true, oauthConnected: provider === "OAuth" },
|
||||||
|
"/api/gist/source/311fc9": { __status: 403, body: { error: provider === "App" ? "github_app_reconnect_required" : "github_oauth_required" } },
|
||||||
});
|
});
|
||||||
const input = await ui.input("#sourceUrl", "https://gist.github.com/311fc9");
|
const input = await ui.input("#sourceUrl", "https://gist.github.com/311fc9");
|
||||||
input.dispatchEvent(new ui.window.Event("blur"));
|
input.dispatchEvent(new ui.window.Event("blur"));
|
||||||
await delay(60);
|
await delay(60);
|
||||||
const button = [...ui.window.document.querySelectorAll("button")].find(node => node.textContent.includes("Connect GitHub OAuth to access gists"));
|
const button = [...ui.window.document.querySelectorAll("button")].find(node => node.textContent.includes(`Connect GitHub ${provider} to access gists`));
|
||||||
expect(button).not.to.equal(undefined);
|
expect(button).not.to.equal(undefined);
|
||||||
expect(ui.requests.some(r => r.url.pathname === "/api/gist/source/311fc9")).to.equal(false);
|
expect(button.closest(".anonymize-workspace")).not.to.equal(null);
|
||||||
|
for (let node = button; node; node = node.parentElement) {
|
||||||
|
expect(ui.window.getComputedStyle(node).display, node.className).not.to.equal("none");
|
||||||
|
}
|
||||||
|
expect(ui.requests.some(r => r.url.pathname === "/api/gist/source/311fc9")).to.equal(true);
|
||||||
button.click();
|
button.click();
|
||||||
const saved = JSON.parse(ui.window.sessionStorage.getItem("github-access-draft"));
|
const saved = JSON.parse(ui.window.sessionStorage.getItem("github-access-draft"));
|
||||||
expect(saved.path).to.equal("/gist-anonymize");
|
expect(saved.path).to.equal("/gist-anonymize");
|
||||||
@@ -487,6 +493,25 @@ describe("Vue 3 UI", function () {
|
|||||||
expect(ui.errors).to.deep.equal([]);
|
expect(ui.errors).to.deep.equal([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
it("previews a gist with only an App login", async function () {
|
||||||
|
ui = await browser("/gist-anonymize", {
|
||||||
|
"/api/user": { username: "owner" },
|
||||||
|
"/github/connections": { appEnabled: true, appConnected: true, gistConnection: "github-app", oauthEnabled: true, oauthConnected: false },
|
||||||
|
"/api/user/default": { terms: [], options: { content: true } },
|
||||||
|
"/api/anonymize-preview": request => ({ contents: request.payload.contents }),
|
||||||
|
"/api/gist/source/311fc9": { gist: { description: "App gist", files: [{ filename: "example.txt", content: "example" }], comments: [] } },
|
||||||
|
});
|
||||||
|
const input = await ui.input("#sourceUrl", "https://gist.github.com/311fc9");
|
||||||
|
input.dispatchEvent(new ui.window.Event("blur"));
|
||||||
|
await delay(300);
|
||||||
|
expect(ui.requests.some(r => r.url.pathname === "/api/gist/source/311fc9")).to.equal(true);
|
||||||
|
expect(ui.window.document.body.textContent).to.include("example.txt");
|
||||||
|
expect(ui.window.document.body.textContent).not.to.include("Connect GitHub OAuth to access gists");
|
||||||
|
expect(ui.errors).to.deep.equal([]);
|
||||||
|
});
|
||||||
|
|
||||||
for (const status of ["archived", "preparing", "queue", "download", "removing", "expiring"]) {
|
for (const status of ["archived", "preparing", "queue", "download", "removing", "expiring"]) {
|
||||||
it(`hides connection changes on ${status} resources`, async function () {
|
it(`hides connection changes on ${status} resources`, async function () {
|
||||||
ui = await browser("/connections", {
|
ui = await browser("/connections", {
|
||||||
|
|||||||
Reference in new issue
Block a user